iPhone Delegate Gotchas and Best Practices
I feel like Newton must have felt when the theory of gravity presented itself to him.  I witnessed an event that I've observed many times before but never understood, but this time I noticed an important characteristic of the event I had missed all those other times.  This new perspective has changed everything I know about multi-threaded programming in a reference-counted environment.

The use of callbacks, or delegate methods in the parlance of Objective-C, is the keystone of the asynchronous processing model.  Delegates make up the very foundations of the iPhone SDK.  Without delegates, the thread model would be more complex, and the resulting developer madness would turn us all away or lead to a high incidence of thread safety problems in the app offering.

When I use callbacks in asynchronous code, my best practice is to use a protocol instead of a concrete class.  This allows any class to easily implement the protocol, resulting in a highly flexible architecture.  It's important to note here that delegates differ from listeners in that there is a one-to-one relationship between the process and its delegate, whereas a process can have many listeners.

A common approach to defining a delegate instance variable (ivar) is to define a property as follows:
@property (assign) id<SomeDelegate> delegate;
Note the use of the assign keyword.  There is a critical expectation here that the delegate object itself is retained by some other external object.  If the delegate object is released externally before the process completes and executes a delegate method, the retain count on the delegate object will drop to zero and the object will be freed, resulting in a bad access error when the process executes the delegate method.

At first glance, you might suggest changing the property definition to retain, instead of assign.  If you do that, you do indeed prevent the bad access error, but you require the delegate object to be released itself inside each delegate method.  This can lead to code maintenance problems as the developer must decide whether or not the delegate should be released based on situational clues and document review.  Further, if nothing else has a retain count on the delegate object when a method is called, the object is immediately freed when the delegate method returns, taking with it any information carried in the delegate method payload.

Still, even if we follow the assign approach, there is no guarantee of thread safety, nor prevention of bad access.  My eureka moment was in realizing that passing the caller object itself as an argument in a delegate method exposes a potential bad access error, should the delegate object assign the caller as an ivar.  Here's an example:

@protocol SomeDelegate;

@interface SomeObject <SomeDelegate> {
id<SomeDelegate> delegate;
}
-(void)process;
-(int)getOne;
@end

@protocol SomeDelegate
-(void)someObject:(SomeObject*)obj finishedProcessingWithSuccess:(BOOL)success;
@end

@implementation SomeObject
@synthesize delegate;
-(void)process
{
  // do something meaningful
  ;
}

-(int)getOne
{
  return 1;
}
@end


The above code defines the processing object and its delegate.  Now, let's add the delegate code:

@interface SomeDelegateInstance <SomeDelegate> {
  SomeObject* someObject;
}
@property (assign) SomeObject* someObject;
@end

@implementation SomeDelegateInstance
@synthesize someObject;
-(void)someObject:(SomeObject*)obj finishedProcessingWithSuccess:(BOOL)success
{
  self.someObject = obj;
}
-(void)printSomeObject
{
  int tOne = ;
  NSLog(@"%d",tOne);
}
@end


In the above scenario, calling printSomeObject on an instance of SomeDelegateInstance after the delegate method is called will result in a bad access, because at this point, the someObject ivar has been assigned a non-nil value, but the object it points to has been freed.

Again, you might suggest simply defining the someObject ivar with retain instead of assign, and you would again be correct that this would eliminate the bad access error.  However, this carries the unfortunate side effect of delaying release of the memory allocated to perform the process until the delegate is set to nil.  This is clearly not ideal, especially in cases where the process uses a large amount of memory.

I offer a more compelling solution.  There are few reasons to pass the caller in to a delegate method as an argument.  Until today, I have used this pattern access the caller's ivars, as an alternative to explicitly defining them in the delegate method signature.  Today, I decided to refactor any code that uses this pattern, in favor of explicitly returning relevant objects as delegate method arguments.  This way, if I need to retain one of these objects in the delegate, I am only retaining the small chunk of memory assigned to the field, and not the larger chunk assigned to the caller.