Во-первых, я новичок на этом сайте, поэтому заранее благодарю за помощь.
В моем приложении для iPhone есть класс, главная роль которого заключается в том, чтобы инкапсулировать способ обработки данных в паре необработанных байтов, поступающих с веб-сервера. Каждый раз, когда мне нужно отобразить определенный тип информации из этих данных (например, совет, содержащийся в этих необработанных байтах), я вызываю метод getAdviceFromGame. Этот метод создает отображаемую NSString путем вызова метода класса NSString в конце (объект, отправленный обратно методом класса stringWithUTF8String, автоматически высвобождается в соответствии с правилами именования методов - без инициализации, без выделения в имени). Обратите внимание, что я не добавил "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];
}
Этот метод, если с моей точки зрения, не критичен с точки зрения управления памятью, поскольку я отправляю обратно только "автоматически освобожденный" объект. Примечание: pGame является внутренней переменной класса типа NSData.
В моем приложении, чтобы понять, как ведут себя автоматически выпущенные объекты, я зациклил 10000 раз этот метод в функции приложения - (void) applicationDidFinishLaunching: (UIApplication *), а также 10000 раз тем же методом в - (void) tabBarController : (UITabBarController *) tabBarController didSelectViewController: (UIViewController *) viewController. Таким образом, я могу использовать большие ассигнования.
Во время выполнения кода, когда приложение запускается, я вижу с помощью инструмента измерения alloc, что размер выделенного объекта увеличивается (с 400K до 800K). Затем, когда метод 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. Ну, я не удовлетворен тем, как это сделать, но, возможно, это правильный путь.
Таким образом, мой последний вопрос: это правильный способ сделать это?
Боюсь, что пул авто-релиза будет очищен до достижения stringWithString: cardSymbol.
С наилучшими пожеланиями,
Franz