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 (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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to