On May 24, 2014, at 5:04 PM, Jens Alfke <j...@mooseyard.com> wrote: > On May 24, 2014, at 2:34 PM, Jamie Ojomoh <jamie.ojo...@gmail.com> wrote: > >> In the example, everything inside the autoreleasepool block will be >> released as soon as the block ends, so it's necessary to declare the return >> value outside the block. > > No, in general ARC understands that the return value needs to keep a > reference, so it’s safe to put the return statement inside the autorelease > block. In your specific example, returnString was allocated before you > created your autorelease pool, so that pool won’t release it anyway. Also, > you allocated returnString using an alloc/init sequence so it’s not in an > autorelease pool at all.
This isn't strictly true; when you are returning objects by reference, doing so inside the @autoreleasepool will cause a crash. For example: #import <Foundation/Foundation.h> static BOOL DoSomethingElse(NSError *__autoreleasing *error) { if (error) *error = [[NSError alloc] initWithDomain:@"Foo" code:-1 userInfo:nil]; return NO; } static BOOL DoSomething(NSError *__autoreleasing *error) { @autoreleasepool { return DoSomethingElse(error); } } int main(int argc, const char * argv[]){ @autoreleasepool { NSError *error = nil; if (DoSomething(&error)) { NSLog(@"Success"); } else { NSLog(@"Error: %@", error); // crashes here } } return 0; } Interestingly, this still happens even if you declare the NSError variable out of the @autoreleasepool block: #import <Foundation/Foundation.h> static BOOL DoSomethingElse(NSError *__autoreleasing *error) { if (error) *error = [[NSError alloc] initWithDomain:@"Foo" code:-1 userInfo:nil]; return NO; } static BOOL DoSomething(NSError *__autoreleasing *error) { NSError *theError = nil; @autoreleasepool { if (DoSomethingElse(&theError)) { return YES; } else { if (error) *error = theError; return NO; } } } int main(int argc, const char * argv[]){ @autoreleasepool { NSError *error = nil; if (DoSomething(&error)) { NSLog(@"Success"); } else { NSLog(@"Error: %@", error); // still crashes here } } return 0; } The only thing that avoids the crash is returning outside of the @autoreleasepool block: #import <Foundation/Foundation.h> static BOOL DoSomethingElse(NSError *__autoreleasing *error) { if (error) *error = [[NSError alloc] initWithDomain:@"Foo" code:-1 userInfo:nil]; return NO; } static BOOL DoSomething(NSError *__autoreleasing *error) { BOOL success; NSError *theError = nil; @autoreleasepool { success = DoSomethingElse(&theError); } if (success) { return YES; } else { if (error) *error = theError; return NO; } } int main(int argc, const char * argv[]){ @autoreleasepool { NSError *error = nil; if (DoSomething(&error)) { NSLog(@"Success"); } else { NSLog(@"Error: %@", error); // now this actually works } } return 0; } The thing that makes this really insidious is that you only get the crash when an error occurs, so if you have an error case that only happens a tiny percentage of the time, it can slip through your testing. Charles _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com