Home > iPhone SDK > Differences in Delegation
Differences in Delegation
Posted on Sunday, March 29, 2009 by android apps market for tablests
Cocoa and Cocoa Touch obviously have a lot in common. They use the same underlying language, they both utilize Foundation classes, and they both follow many of the same design patterns. The fact that they are designed to work for different kinds of physical hardware and the fact that Cocoa Touch was created nearly twenty years after Cocoa (n�e NexSTEP), means that there are some areas that are very different. These differences can throw you, since so much between the two is the same.
The most obvious of these differences is that the concept of generic view controller classes is "baked in" to Cocoa Touch, but were added to Cocoa after it had been around for years. But that's a topic for a separate blog posting. Today, I want to talk about another, slightly more subtle difference, which is that Cocoa and Cocoa Touch implement delegates in completely different ways. Let's look at the most commonly used delegate objects: the application delegates. The two frameworks' application delegates�UIApplicationDelegate and NSApplicationDelegate� serve the same purpose, but are implemented differently.
Delegation is not unique to Objective-C. It's a recognized pattern that is used in many languages, albeit sparingly in most. Because of Objective-C's dynamic, loosely typed nature, the Apple and NeXT engineers realized early on that delegation was often a better choice than inheritance, which is why the class hierarchy for Cocoa and Cocoa Touch is generally flatter than the hierarchies of object-oriented application frameworks built in other languages. If you have come to Objective-C recently from another OO language, whenever your first impulse is to subclass, take a step back and ask yourself if another design pattern, like delegation or a category, doesn't fit better in light of the language you are using.
Anyway, back to the application delegates. The big difference between UIApplicationDelegate and NSApplicationDelegate is in what they are. NSApplicationDelegate is an informal protocol, which means that it's simply a category on NSObject. Below, you can see what NSApplicationDelegate looks like in Leopard. I have taken out comments and pre-compiler macros and reformatted it to make it easier to read. You can find the original in <Cocoa/NSApplication.h>:
This may seem rather odd. Why would we declare a category on NSObject for delegate methods? Depending on your language background, you might be wondering why this isn't a protocol or interface. The answer is simple, really. In Objective-C prior to 2.0, protocols (sometimes referred to as "formal protocols") did not allow optional methods. If you conformed to a protocol, you had to implement every method in that protocol. That wouldn't have worked very well; the Apple and NeXT engineers didn't want to force programmers to respond to every conceivable method any application delegate would ever need in their own delegates. Rather, they wanted to let programmers implement only the delegate methods that they needed. By declaring it as a category and creating what we call an "informal protocol", the compiler and the programmer are told what methods this delegate can respond to, but no obligation is imposed on the programmer to implement any particular method. It's perfectly valid (though silly) for a delegate to respond to none of the delegate methods.
In the Cocoa approach to delegates, the mutator method for a delegate usually looks like this:
In other words, an instance of any class can be set as the delegate. If that delegate implements a particular delegate method, that method will be called at the appropriate time. If it doesn't implement it, NSApplication will simply skip the call and continue execution of the program. It's a very laissez-faire approach that puts a lot of trust in the programmer. That's Cocoa in a nutshell, really. Objective-C doesn't give the programmer mechanisms to completely lock out other programmers the way, say, Java, C++, and C# do. There are no final classes, and declaring things @private is really more of a suggestion. The nature of the language leads to a different approach to many things. It may seem weird - even wrong - if you come from one of the many languages that derive their object-model from the far-less-trusting Simula, but give it time. Properly used, it's very elegant.
On the other hand. UIApplicationDelegate, the iPhone's application delegate, is not implemented using a category, it's implemented using a formal protocol. Since the iPhone was developed after Objective-C 2.0 was released, Apple had the option of using optional methods in formal protocols, so in Cocoa Touch most (I think all) delegates are defined as formal protocols. This is what the application delegate looks like in Cocoa Touch. Again, I have reformatted and removed comments to make it read easier in this context:
It's really not all that different. Of course, the delegate methods are not exactly the same due to the different nature of the devices for which Cocoa and Cocoa Touch were designed, but this protocol says basically the same that our earlier informal protocol said: that any object can be a delegate, and since it declares all of the methods as @optional, the delegate only needs to implement those methods it cares about. The mutator method for a delegate in Cocoa Touch looks similar to the one in Cocoa, but with two differences. First, UIApplication uses Objective-C 2.0's properties and synthesizes the mutator rather than declaring a mutator manually. Second, and more important, though it still accepts id (meaning any object), it requests that the object being assigned as the delegate conform to the UIApplicationDelegate protocol:
This being Objective-C, you actually can assign any object to be the delegate, even one that doesn't conform to the protocol, but if the assigned object's class doesn't explicitly conform to UIApplicationDelegate, you will get a compile-time warning. Fortunately, all the iPhone application templates give you your application delegate, and the provided delegate's class already conforms to that property, so you rarely ever need to do that step for the application delegate, but when it comes to the countless other delegates in Cocoa Touch, you will need to explicitly conform your class to the delegate protocol.
Whether Cocoa will switch to using formal protocols is, as of now, an unanswered question. So far, I've seen no indication of Apple making this change. As of Leopard, every delegate I can think of is implemented as a category on NSObject, but I also don't have any more information about what's going in inside the loop than most of you do and don't know if they have plans to change this. They might. They might not.
What I do know is that not everybody agrees that the newer way of doing delegates is better. I've talked to a number of old-time Cocoa/Mac programmers who view the new approach as less elegant and see it as an unnecessary change. I don't really have much of an opinion, to be honest. As a practical matter, there's not much of a difference in the way we use delegates with either approach. Other than conforming our classes to one protocol, pretty much everything works the same.
The new approach is a tradeoff. It adds some compiler-time checks that aren't available with informal protocols, but it also has some unintended consequences. For example, when you have subclasses of classes with delegates, you can have situations where a delegate has to conform to a protocol for an object for which it's not the delegate. You can see an example of this in Beginning iPhone Development in Chapter 16. On page 467, we conform CameraViewController to UINavigationControllerDelegate, even though we're not a delegate of a UINavigationController. Why? Because UIImagePickerController is a subclass of UINavigationController. Because both of those classes have delegates, and their delegates require different protocols. As a result, the compiler forces us to conform to both protocols. It's a pretty minor inconvenience - it requires typing a single class name - but this seems to rub some Cocoa developers I've talked to as being very "un-Cocoa-like" and inelegant.
Let's finish off with one important last bit of information about delegates that applies to both Cocoa and Cocoa Touch: as a general rule, objects do not send a -retain message to their delegate. There are a few exceptions to this, but unless a class is specifically documented as retaining its delegate, assume that they don't. If your delegate gets deallocated before the class it is a delegate for, you should make sure to set the class' delegate to nil before your class is deallocated to avoid problems.
The most obvious of these differences is that the concept of generic view controller classes is "baked in" to Cocoa Touch, but were added to Cocoa after it had been around for years. But that's a topic for a separate blog posting. Today, I want to talk about another, slightly more subtle difference, which is that Cocoa and Cocoa Touch implement delegates in completely different ways. Let's look at the most commonly used delegate objects: the application delegates. The two frameworks' application delegates�UIApplicationDelegate and NSApplicationDelegate� serve the same purpose, but are implemented differently.
Delegation is not unique to Objective-C. It's a recognized pattern that is used in many languages, albeit sparingly in most. Because of Objective-C's dynamic, loosely typed nature, the Apple and NeXT engineers realized early on that delegation was often a better choice than inheritance, which is why the class hierarchy for Cocoa and Cocoa Touch is generally flatter than the hierarchies of object-oriented application frameworks built in other languages. If you have come to Objective-C recently from another OO language, whenever your first impulse is to subclass, take a step back and ask yourself if another design pattern, like delegation or a category, doesn't fit better in light of the language you are using.
Anyway, back to the application delegates. The big difference between UIApplicationDelegate and NSApplicationDelegate is in what they are. NSApplicationDelegate is an informal protocol, which means that it's simply a category on NSObject. Below, you can see what NSApplicationDelegate looks like in Leopard. I have taken out comments and pre-compiler macros and reformatted it to make it easier to read. You can find the original in <Cocoa/NSApplication.h>:
@interface NSObject(NSApplicationDelegate)
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames;
- (BOOL)application:(NSApplication *)sender openTempFile:(NSString *)filename;
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender;
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
- (BOOL)application:(id)sender openFileWithoutUI:(NSString *)filename;
- (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename;
- (NSApplicationPrintReply)application:(NSApplication *)application
printFiles:(NSArray *)fileNames
withSettings:(NSDictionary *)printSettings
showPrintPanels:(BOOL)showPrintPanels;
- (void)application:(NSApplication *)sender printFiles:(NSArray *)filenames;
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender;
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag;
- (NSMenu *)applicationDockMenu:(NSApplication *)sender;
- (NSError *)application:(NSApplication *)application willPresentError:(NSError *)error;
@endThis may seem rather odd. Why would we declare a category on NSObject for delegate methods? Depending on your language background, you might be wondering why this isn't a protocol or interface. The answer is simple, really. In Objective-C prior to 2.0, protocols (sometimes referred to as "formal protocols") did not allow optional methods. If you conformed to a protocol, you had to implement every method in that protocol. That wouldn't have worked very well; the Apple and NeXT engineers didn't want to force programmers to respond to every conceivable method any application delegate would ever need in their own delegates. Rather, they wanted to let programmers implement only the delegate methods that they needed. By declaring it as a category and creating what we call an "informal protocol", the compiler and the programmer are told what methods this delegate can respond to, but no obligation is imposed on the programmer to implement any particular method. It's perfectly valid (though silly) for a delegate to respond to none of the delegate methods.
In the Cocoa approach to delegates, the mutator method for a delegate usually looks like this:
- (void)setDelegate:(id)anObject;In other words, an instance of any class can be set as the delegate. If that delegate implements a particular delegate method, that method will be called at the appropriate time. If it doesn't implement it, NSApplication will simply skip the call and continue execution of the program. It's a very laissez-faire approach that puts a lot of trust in the programmer. That's Cocoa in a nutshell, really. Objective-C doesn't give the programmer mechanisms to completely lock out other programmers the way, say, Java, C++, and C# do. There are no final classes, and declaring things @private is really more of a suggestion. The nature of the language leads to a different approach to many things. It may seem weird - even wrong - if you come from one of the many languages that derive their object-model from the far-less-trusting Simula, but give it time. Properly used, it's very elegant.
On the other hand. UIApplicationDelegate, the iPhone's application delegate, is not implemented using a category, it's implemented using a formal protocol. Since the iPhone was developed after Objective-C 2.0 was released, Apple had the option of using optional methods in formal protocols, so in Cocoa Touch most (I think all) delegates are defined as formal protocols. This is what the application delegate looks like in Cocoa Touch. Again, I have reformatted and removed comments to make it read easier in this context:
@protocol UIApplicationDelegate<NSObject>
@optional
- (void)applicationDidFinishLaunching:(UIApplication *)application;
- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)applicationWillResignActive:(UIApplication *)application;
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url;
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application;
- (void)applicationWillTerminate:(UIApplication *)application;
- (void)applicationSignificantTimeChange:(UIApplication *)application;
- (void)application:(UIApplication *)application
willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation
duration:(NSTimeInterval)duration;
- (void)application:(UIApplication *)application
didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation;
- (void)application:(UIApplication *)application
willChangeStatusBarFrame:(CGRect)newStatusBarFrame;
- (void)application:(UIApplication *)application
didChangeStatusBarFrame:(CGRect)oldStatusBarFrame;
@end
It's really not all that different. Of course, the delegate methods are not exactly the same due to the different nature of the devices for which Cocoa and Cocoa Touch were designed, but this protocol says basically the same that our earlier informal protocol said: that any object can be a delegate, and since it declares all of the methods as @optional, the delegate only needs to implement those methods it cares about. The mutator method for a delegate in Cocoa Touch looks similar to the one in Cocoa, but with two differences. First, UIApplication uses Objective-C 2.0's properties and synthesizes the mutator rather than declaring a mutator manually. Second, and more important, though it still accepts id (meaning any object), it requests that the object being assigned as the delegate conform to the UIApplicationDelegate protocol:
@property(nonatomic,assign) id<UIApplicationDelegate> delegate;This being Objective-C, you actually can assign any object to be the delegate, even one that doesn't conform to the protocol, but if the assigned object's class doesn't explicitly conform to UIApplicationDelegate, you will get a compile-time warning. Fortunately, all the iPhone application templates give you your application delegate, and the provided delegate's class already conforms to that property, so you rarely ever need to do that step for the application delegate, but when it comes to the countless other delegates in Cocoa Touch, you will need to explicitly conform your class to the delegate protocol.
Whether Cocoa will switch to using formal protocols is, as of now, an unanswered question. So far, I've seen no indication of Apple making this change. As of Leopard, every delegate I can think of is implemented as a category on NSObject, but I also don't have any more information about what's going in inside the loop than most of you do and don't know if they have plans to change this. They might. They might not.
What I do know is that not everybody agrees that the newer way of doing delegates is better. I've talked to a number of old-time Cocoa/Mac programmers who view the new approach as less elegant and see it as an unnecessary change. I don't really have much of an opinion, to be honest. As a practical matter, there's not much of a difference in the way we use delegates with either approach. Other than conforming our classes to one protocol, pretty much everything works the same.
The new approach is a tradeoff. It adds some compiler-time checks that aren't available with informal protocols, but it also has some unintended consequences. For example, when you have subclasses of classes with delegates, you can have situations where a delegate has to conform to a protocol for an object for which it's not the delegate. You can see an example of this in Beginning iPhone Development in Chapter 16. On page 467, we conform CameraViewController to UINavigationControllerDelegate, even though we're not a delegate of a UINavigationController. Why? Because UIImagePickerController is a subclass of UINavigationController. Because both of those classes have delegates, and their delegates require different protocols. As a result, the compiler forces us to conform to both protocols. It's a pretty minor inconvenience - it requires typing a single class name - but this seems to rub some Cocoa developers I've talked to as being very "un-Cocoa-like" and inelegant.
Let's finish off with one important last bit of information about delegates that applies to both Cocoa and Cocoa Touch: as a general rule, objects do not send a -retain message to their delegate. There are a few exceptions to this, but unless a class is specifically documented as retaining its delegate, assume that they don't. If your delegate gets deallocated before the class it is a delegate for, you should make sure to set the class' delegate to nil before your class is deallocated to avoid problems.
Category Article Cocoa, Cocoa Touch, Delegates, iPhone SDK
Powered by Blogger.
Blog Archive
-
▼
2009
(496)
-
▼
March
(36)
- Introducing Google Brain Search for mobile
- Speed with a Catch
- Apple Packaging
- Mobile internet usage and useful mobile ads
- WWDC First Time Guide
- WWDC Accommodations
- Wavefront OBJ Loader Open Sourced to Google Code
- Apple Store LA Book Sighting
- Differences in Delegation
- Icons for Multiple Developer Tool Installs
- NSConference
- Xcode Single Window Mode
- The Greatest Week of the Year
- WWDC Was Announced - June 8 - 12
- One Year In
- Limiting Text Field Input
- Look Ma, No Hands - Google Mobile App for Blackber...
- Updated to the Kotaku / Refund Clause Issue
- Kotaku and the Technicolor Contract Clause
- Rumor Mill
- Resuable Reusable Classes
- Guess Where These Were Taken�
- Magnifying Glass in a Text View inside a Table Vie...
- Image Processing on the iPhone
- A Freebie
- Version Control is Your Friend
- New YouTube App for Windows Mobile and Nokia S60 p...
- Something I CAN Tell You...
- Wish I Could Say More
- A Word of Caution about SDK 3.0
- On the fate of SQLitePersistentObjects�
- iPhone OS 3.0
- Particle Generator Bugfixes
- Here comes Google Voice
- New Image Search Results for Android and iPhone
- Finance for Android App
-
▼
March
(36)