Во-первых, я новичок на этом сайте, поэтому заблаговременно за вашу помощь.Метод класса: это правильный способ избежать утечки памяти?
У моего приложения iPhone есть класс, основная роль которого заключается в том, чтобы инкапсулировать способ обработки данных на кучу необработанных байтов, поступающих с веб-сервера. Каждый раз, когда мне нужно отображать определенный тип информации из этих данных (например, совет, содержащийся в этих необработанных байтах), я вызываю метод getAdviceFromGame. Этот метод создает отображаемую NSString, вызывая метод класса NSString в конце (объект, отправленный обратно методом класса stringWithUTF8String, автореализован, в соответствии с правилами именования метода - нет init, нет выделения в имени). Обратите внимание, что я не помещал «New» в имя моего метода, потому что вызывающий объект не имеет объект, отправленный обратно методом.
Вот метод:
-(NSString*) getAdviceFromGame:(NSInteger)number
ofLine:(NSInteger)line {
// Returns the advice at line specified as argument.
NSInteger currentOffset;
NSRange currentRange;
NSInteger offsetAdvice;
NSInteger length;
char currentCString[100];
if (line == 1)
offsetAdvice = OFF_ADVICE1;
else
offsetAdvice = OFF_ADVICE2;
// Length is the same whateve is the line.
length = LEN_ADVICE1;
// Point to the begnning of the requested game.
currentOffset = OFF_G1_SET + (number - 1) * LEN_SET;
// Point to the selected advice.
currentOffset = currentOffset + offsetAdvice;
// Skip TL
currentOffset = currentOffset + 2;
currentRange.location = currentOffset;
currentRange.length = length;
NSLog(@"Avant getBytes");
// Get raw bytes from pGame.
// Contains a C termination byte.
[pGame getBytes:currentCString range:currentRange];
// Turn these raw bytes into an NSString.
// We return an autoreleased string.
return [NSString stringWithUTF8String:currentCString];
}
Этот метод, если с моей точки зрения, не имеет решающего значения, с точки зрения управления памятью зрения, так как я только отправить обратно «autoreleased» объект , Примечание: pGame - это внутренняя переменная класса типа NSData.
В моем приложении, чтобы понять, как себя ведут себя автореализованные объекты, я запустил 10000 раз этот метод в приложении приложения (void) applicationDidFinishLaunching: (UIApplication *), а также в 10000 раз по тому же методу в - (void) tabBarController: (UITabBarController *) tabBarController сделалSelectViewController: (UIViewController *) viewController. Таким образом, я могу вызвать большие выделения.
Во время выполнения кода, когда приложение запущено, я могу видеть с помощью инструмента измерения распределения, что размер выделенного объекта увеличивается (от 400 К до 800 КБ). Затем, когда метод applicationDidFinishLaunching завершается, сумма уменьшается до 400K. Таким образом, я предполагаю, что пул был «истощен» операционной системой (вид управления мусором).
Когда я нажимаю на панель вкладок, снова появляется большое выделение из-за цикла. Кроме того, я вижу, что размер растет (потому что тысячи NSString выделены и отправлены обратно). Когда это будет сделано, размер уменьшится до 400K.
Таким образом, мои первые вопросы: Q1: Можем ли мы точно знать, когда пул авторесурсов будет «истощен» или «очищен»? Q2: Это происходит в конце методов OS/GUI, таких как didSelectViewController? Q3: Должен ли кто-то, вызывающий getAdviceFromGame, сохранить объект, отправленный обратно моим методом, прежде чем использовать его?
Теперь у меня есть другой (более сложный) способ, в котором я внутренне выделить изменяемую строку, в которой я работаю, прежде чем отправить обратно NSString:
-(NSString*) getBiddingArrayFromGame:(NSInteger)number
ofRow:(NSInteger)row
ofLine:(NSInteger)line {
NSInteger offset;
char readByte;
NSMutableString *cardSymbol = [[NSMutableString alloc] initWithString:@""];
NSRange range;
// Point to the begnning of the requested game.
offset = OFF_G1_SET + (number - 1) * LEN_SET;
// Returns the array value from cell (row, line)
// We must compute the offset of the line.
// We suppose that the offset cannot be computed, but
// only deduced from line number through a table.
switch (line) {
case 1:
offset = offset + OFF_LINE1;
break;
case 2:
offset = offset + OFF_LINE2;
break;
case 3:
offset = offset + OFF_LINE3;
break;
case 4:
offset = offset + OFF_LINE4;
break;
default:
// This case should not happen but for robustness
// we associate any extra value with a valid offset.
offset = OFF_LINE4;
break;
}
// Skip TL bytes
offset = offset + 2;
// From the offset and from the row value, we can deduce
// the offset in the selected line.
offset = offset + (row - 1);
// Now, we must read the byte and build a string from
// the byte value.
range.location = offset;
range.length = 1;
[pGame getBytes:&readByte range:range];
// We must extract the family type.
// If the family if of type "Special" then we must build by
// hand the value to display. Else, we must build a string
// with the colour symbol and associated character by reading
// in the card character table.
switch (readByte & CARD_FAMILY_MASK) {
case COLOUR_CLUBS:
// "Trèfles" in French.
[cardSymbol appendString:CLUBS_UTF16];
break;
case COLOUR_DIAMONDS:
[cardSymbol appendString:DIAMONDS_UTF16];
break;
case COLOUR_HEARTS:
[cardSymbol appendString:HEARTS_UTF16];
break;
case COLOUR_SPADES:
[cardSymbol appendString:SPADES_UTF16];
break;
case COLOUR_SPECIAL:
break;
case COLOUR_ASSET:
default:
break;
}
[cardSymbol autorelease];
// Return the string.
return [NSString stringWithString:cardSymbol];
}
Как вы можете видеть, это не является очень сложным, но более критичным с точки зрения управления памятью, поскольку я «внутренне» выделяю и запускаю NSString. Поскольку я использую его в конце метода, я могу только автоопределить его перед вызовом stringWithString: cardSymbol (на самом деле я бы хотел его освободить, чтобы он был освобожден прямо сейчас), иначе он может быть освобожден до использования метода stringWithString: cardSymbol. Ну, я не удовлетворен тем, как это сделать, но, возможно, это правильный способ сделать это.
Таким образом, мой последний вопрос: это правильный способ сделать это?
Я боюсь, что пул авторефератов будет очищен до достижения строки. Стойка: cardSymbol.
С наилучшими пожеланиями, Franz
@Yuji: Спасибо за советы по поводу наименования метода («получить» или «получить», я не знал разницы). После публикации вопроса, я получил ту же идею, чтобы выпустить cardSymbol внутри метода, используя альтернативный указатель NSString, чьи данные, указанные им, могут быть освобождены до «возврата». NSString * s = [SString stringWithString: cardSymbol]; [cardSymbol release]; return s; карточка возвратаSymbol; : Действительно, я не знал, что могу вернуть подкласс возвращаемого типа. – user255607
Спасибо за ваш ответ. Я заметил, что в последнем примере я забыл «autorelease», который я исправил сейчас. Глупый я. – Yuji