Leak or Crash - difference between autorelease and

2019-05-26 17:49发布

问题:

I have a comprehension question. This method is given:

- (NSArray*)test {
 NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://stackoverflow.com/"]];
 NSString *result = [[NSString alloc] initWithBytes:[data bytes] 
            length:[data length] 
             encoding:NSMacOSRomanStringEncoding];
 result = [result stringByAppendingString:@"something"];
 NSArray *arr = [NSArray arrayWithObject:result];
 //[result release];
 return arr;
}

If I uncomment the release the App would crash and say it cannot access a released object.
By not releaseing the result string Instruments would report a leak (NSPlaceholderString).

I can autorelease it on the same line I alloc it, that would solve the problem (which I'm currently doing in my App).

If I understand it correctly stringByAppendingString: should create an autoreleased object so the 'old' result could be deallocated. Then the method arrayWithObject: should copy the object into an array. So my thought was to release the string after it was copied to the array.

Am I missing something or something wrong with my knowledge?

回答1:

Let's go through your code line by line.

- (NSArray*)test {
 NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://stackoverflow.com/"]];

This creates a data object. You don't own it, but it will stick around for the rest of the method's time. So far, so good.

 NSString *result = [[NSString alloc] initWithBytes:[data bytes] 
                                             length:[data length] 
                                           encoding:NSMacOSRomanStringEncoding];

This creates a string object that you own. Again, no problem here — we just need to release it later.

result = [result stringByAppendingString:@"something"];

You throw away your reference to the string object that was in result and store a new string object that you do not own. This is a leak because you can no longer release the original string. Also, you're correct in noting that the new string can be treated as an autoreleased object — which means you should not release it.

NSArray *arr = [NSArray arrayWithObject:result];

Contrary to your belief, this does not copy anything. It merely keeps a reference to the new string and retains it.

//[result release];

You should not release result at this point, because the object it contains is not one you own — you got it from stringByAppendingString:, not from a method with new, alloc, retain or copy in its name. Releasing this object that you do not own will almost certainly result in a crash at some point. The old object that you own and should release was lost two lines earlier, and releasing something else in its place won't help.



回答2:

result = [result stringByAppendingString:@"something"];

This line replaces the first allocated string by a new autoreleased string.

So the first string is leaked and the second one should not be released. This explains why uncommenting the release line crashes.