Re: Autorelease and passing by reference in background threads
Re: Autorelease and passing by reference in background threads
- Subject: Re: Autorelease and passing by reference in background threads
- From: Michael Ash <email@hidden>
- Date: Tue, 28 Apr 2009 01:00:02 -0400
On Mon, Apr 27, 2009 at 3:17 PM, Symphonik <email@hidden> wrote:
> All,
>
> I am using a couple of methods that use NSError ** pointers to communicate
> error conditions. These methods run on background threads and so have their
> own autorelease pools set up. I pass an NSError pointer down a couple of
> method calls -- by the time it comes back up, it has been dealloc'd by the
> autorelease pool. A simple example (this will run if you want to try it for
> yourself):
>
> - (void)applicationDidFinishLaunching:(UIApplication *)application {
> [self performSelectorInBackground:@selector(runBackgroundProcess)
> withObject:nil];
> }
>
> - (void)runBackgroundProcess {
> NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
>
> NSError *error = nil;
> [self runSomethingThatWillFail:&error];
>
> if(error) {
> NSLog(@"error: %@", error); // <==== CRASH HERE, EXC_BAD_ACCESS due
> to bogus pointer
> }
>
> [pool release];
> }
>
> - (void)runSomethingThatWillFail:(NSError **)error {
> NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
> NSArray *directoryContents = [[NSFileManager defaultManager]
> contentsOfDirectoryAtPath:@"/BOGUS" error:error];
> [pool release];
> }
>
> So I crash in runBackgroundProcess since the error is getting wiped by the
> local autorelease pool. Okay, so I'll retain it...
>
> - (void)runSomethingThatWillFail:(NSError **)error {
> NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
> NSArray *directoryContents = [[NSFileManager defaultManager]
> contentsOfDirectoryAtPath:@"/BOGUS" error:error];
> [*error retain];
> [pool release];
> }
>
> Well, now I have a leak of that NSError object... so I should autorelease
> it, I suppose. But that autorelease needs to be outside the release of the
> local pool, so it becomes:
>
> - (void)runSomethingThatWillFail:(NSError **)error {
> NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
> NSArray *directoryContents = [[NSFileManager defaultManager]
> contentsOfDirectoryAtPath:@"/BOGUS" error:error];
> [*error retain];
> [pool release];
> [*error autorelease];
> }
>
> Now it works and isn't leaking anymore. But factor in that I have to do some
> checking on the existence of the error before I dereference it, etc... this
> is becoming some ugly code just to get my NSError back up the chain.
>
> Am I overthinking this? Anyone else have better suggestions?
Why does -runSomethingThatWillFail: have its own pool? You already
have a pool, you don't need a second one. Get rid of that pool and
suddenly everything becomes easy.
If it really *must* have a pool for some reason, then the
retain/autorelease dance is the standard procedure for getting
returned objects out of the current pool and into the next one. Think
of that error value as a return value, even though it's returned by
reference and not by value.
Mike
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden