Re: Memory management about async object
Re: Memory management about async object
- Subject: Re: Memory management about async object
- From: Andreas Grosam <email@hidden>
- Date: Sat, 1 Jan 2011 17:00:53 +0100
On Dec 29, 2010, at 5:54 PM, James Bucanek wrote:
> - (void) loadData {
> DataHandler *myHandler = [[DataHandler alloc] init];
> // set this view controller itself as a delegate, when the data loading
> finished, myHandler will call its callback method
> myHandler.delegate = self;
> [myHandler startAsyncLoading];
> [myHandler release];
This is also one of the rare cases where the handler's delegate (the view controller) should be retained when invoking [myHandler setDelegate:self] by the receiver (handler). Otherwise, the view controller could possibly be deallocated before the asynchronous operation completes.
As an example, in Cocoa setting up an animation for a layer with an CAAnimation object shares the same problem pattern. For this case, CAAnimation retains its delegate:
// A view controller's implementation:
- (void) fadeout
{
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; // (autoreleased)
animation.delegate = self; // self will be retained by animation!
animation.fromValue = [NSNumber numberWithFloat:self.view.layer.opacity];
animation.toValue = [NSNumber numberWithFloat:0.0f];
[self.view.layer addAnimation:animation forKey:@"fadeoutAnimation"];
self.view.layer.opacity = 0.0f;
//(animation is autoreleased)
}
// CAAnimation Delegate implementations
- (void)animationDidStart:(CAAnimation *)theAnimation
{ ... }
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{ ... }
There is only one additional thing here which needs to be considered:
The code above also indicates that the object performing the asynchronous task must not be deallocated *before* the delegate method(s) eventually gets invoked, OR the async object must ensure that its delegate gets retained, performs the callback and then gets released again "somehow" when it itself gets deallocated in between. Below is an example how the latter can be accomplished very easily, thanks to Cocoa's well-though-out design:
AsyncObject implementation:
it's assumed that -doSomething is running in a secondary thread:
- (void) doSomething {
// perform some work ...
// finished with work, notify the delegate:
[delegate performSelectorOnMainThread:@selector(callback) withObject:nil waitUntilDone:NO];
}
In the last statement, performSelectorOnMainThread queues the message on the run loop of the main thread, which *retains the receiver* and the argument (here it is nil) and immediately returns. The secondary thread may continue to execute, then exit and thereby all the async object's references will be released and itself deallocated. However, the queued message still waits in the run loop in the main thread. Additionally, the receiver of performSelectorOnMainThread (the delegate) and its argument is still retained *until after* the selector is performed. Using performSelectorOnMainThread ensures that the delegate exists until after the callback has been invoked. :)
(see also -(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)argwaitUntilDone:(BOOL)wait)
Regards
Andreas_______________________________________________
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