Hello,
First, I am new on this website, thus thank you in advance for your help.
My iPhone app has a class whose main role is to encapsulate the way I treat data on a bunch of raw bytes coming from a web server. Each time I need to display a defined type of information from that data (e.g. a piece of advice contained within these raw bytes) I call the method getAdviceFromGame. This method builds a displayable NSString by calling a NSString class method at the end (the object sent back by the stringWithUTF8String class method is autoreleased, according to method naming rules - no init, no alloc in the name). Please note that I did not put "New" in my method name because the caller does not own the object sent back by the method.
Here is the method:
-(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];
}
This method if from my point of view, not critical, from a memory management point of view since I only send back an "autoreleased" object. Note: pGame is an internal class variable of type NSData.
In my app, in order to understand how autoreleased objects behave, I have looped 10000 times this method in the - (void)applicationDidFinishLaunching:(UIApplication *)application function and also 10000 times the same method in - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController. This way, I can invoke big allocations.
During code execution, when the app is launched, I can see with the alloc measurement tool that the allocated object size is growing (from 400K to 800K). Then, when the applicationDidFinishLaunching method ends, then the amount gets down to 400K. Thus I guess that the pool has been "drained" by the operating system (kind of garbage management).
When I click on a tab bar, once again there is a big allocation due to the loop. Also, I can see the size growing (because thousands of NSString are allocated and sent back). When that's done, then the size gets down to 400K.
Thus my first questions are: Q1: Can we precisely know when the autorelease pool will be "drained" or "purged"? Q2: Does this happen at the end of OS/GUI methods such as didSelectViewController? Q3: Must someone who calls getAdviceFromGame retain the object sent back by my method before using it?
Now I have another (more complicated) method where I internally allocate a mutable string on which i am working on before sending back the 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];
}
As you can see, this is not very complicated but more critical from a memory management point of view since I "internally" alloc and init an NSString. Since I use it at the end of the method, I can only autorelease it before calling stringWithString:cardSymbol (in fact I would like to release it so that it is deallocated right now) else it could be deallocated before stringWithString:cardSymbol method. Well I am not satisfied with the way to do this but maybe it is the right way to do it.
Thus my last question is: Is that the right way to do it?
I am afraid that the autorelease pool be purged before reaching stringWithString:cardSymbol.
Best Regards, Franz