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 protected])
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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]