Ipphones

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Sunday, 29 March 2009

Differences in Delegation

Posted on 07:46 by Unknown
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>:

@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;
@end

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:

- (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.
Email ThisBlogThis!Share to XShare to Facebook
Posted in Cocoa, Cocoa Touch, Delegates, iPhone SDK | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • Making OpenGL ES Screenshot
    The Bit-101 Blog has an entry that shows how to take a screenshot when using OpenGL ES . I tested this in my much-delayed particle-generato...
  • Adding CLANG to Your Build Process
    Frasier Spiers has a nifty piece this morning on using Git pre-commit hooks to automatically run the CLANG Static Analyzer. I'm not a G...
  • CLANG Static Analyzer
    If you aren't using the LLVM/Clang Static Analyzer , you really should be. The Clang Project is an attempt to write a front end for the...
  • A Little Help
    I'm having a problem with OpenGL ES, and it's keeping me from finishing my particle engine post. I was hoping someone here could see...
  • WWDC Accommodations
    Staying downtown in San Francisco is very expensive in the summertime. Bu, if you're going to WWDC, you really want to stay downtown. Yo...
  • Xcode File Templates and a Mystery
    One of the things that confuses many newcomers to Xcode is how to set it up so that your company name gets automatically filled in when you ...
  • Brain Surgery?
    Craig Hockenberry has an interesting post on his blog today about the iPhone background processing issue. Craig speaks from personal experi...
  • Book's Almost Done
    I just finished Chapter 16. I'll give it another read-over in the morning then it will go off to my writing partner for his review, then...
  • iPhone Alley
    Looks like Dave and I are going to make an appearance on the iPhone Alley Podcast next week. We're recording on Sunday night, so I woul...
  • Shuffling Arrays
    Ever want to randomize an array of items? It's a task that, for some reason, I've had to do a lot in recent programs. So, I wrote a ...

Categories

  • 3D Models
  • Ad Hoc Distribution
  • ADC
  • Address Book
  • Amazon
  • Anaglyphs
  • App Store
  • Apple
  • Apple DTS
  • Apple Store
  • Application Store
  • articles
  • Award
  • Background Processing
  • Barcodes
  • Beta
  • Blog
  • Blogger
  • Blogging
  • Blogs
  • Blogspot
  • Book project
  • Bug Reporting
  • Captain Obvious
  • Categories
  • Censorship
  • CFFoundation
  • CGAffineTransform
  • Clang Static Analyzer
  • Cocoa
  • Cocoa Touch
  • Code Reuse
  • Code Signing
  • Computer
  • conferences
  • Controller Classes
  • Core Animation
  • Daring Fireball
  • Database
  • Debugging
  • Defect
  • Delegates
  • Design Awards
  • Developer Certifications
  • Discussion Forums
  • Edit Mode
  • employment opportunities
  • Encryption
  • Enterprise
  • Errata
  • free code
  • Free software
  • Full Screen
  • Game Programming
  • Gestures
  • Getting Started
  • goof
  • Google Code
  • Google Maps
  • Gotcha
  • Help
  • HIG
  • HTTP PUT
  • Idiots
  • Idle Timer
  • Images
  • Instruments
  • Interface Builder
  • iPHone
  • iPhone Applications
  • iPhone Dev Center
  • iPhone Developers
  • iPhone OS 3.0
  • iPhone SDK
  • iPhone SDK PNG
  • iPhone Simulator
  • iPhoneSDK
  • iPod
  • Job Opportunities.
  • k
  • Key Value Observing
  • Keynote
  • KVO
  • Landscape Mode
  • Learn Cocoa
  • Learn Cocoa on the Mac
  • libxml
  • Licensing
  • Mac Developers
  • Mac OS X
  • Macworld Expo
  • Microsoft
  • NDA
  • NeHe
  • New Category
  • New Release
  • NSFileHandle
  • NSMutableArray
  • NSMutableURLRequest
  • NSXML
  • Object-Oriented Design
  • Objective-C
  • Open Source
  • OpenGL ES
  • Optimizations
  • Other blogs
  • Paired Arrays
  • Parsing
  • Particle Engine
  • Party
  • PeopleSoft
  • Performance
  • Persistence
  • Pink Screen of Death
  • Piracy
  • Pixar
  • Podcasts
  • Press Release WTF
  • Press Releases WTF
  • private APIs Google
  • Project Template
  • Properties
  • Random Numbers
  • Rant
  • Rejected
  • Resources
  • Responder Chain
  • REST
  • Reverse Engineering
  • Rumors
  • Runtime
  • Sample Code
  • Screencast
  • screenshot
  • Scroll Views
  • snippet
  • Snow Leopard.
  • SOAP
  • Sockets
  • Source
  • Splash Screen
  • SQLite
  • SQLitePersistentObjects
  • Steve Jobs
  • Steve-Note
  • Strings
  • Stupidity
  • Subversion
  • Table Views
  • Taps
  • Template
  • Tip
  • Tips
  • Tririga
  • tutorials
  • Twitter
  • UIAlertView
  • UIColor
  • UIImage
  • UIPickerView
  • UIScrollView
  • UITextField
  • UIView
  • UIWebView
  • Update
  • Utilities
  • UUID
  • Vacation
  • Version Control
  • Web Services
  • Writing
  • WTF
  • WWDC
  • Xcode
  • XML

Blog Archive

  • ▼  2009 (141)
    • ►  May (14)
    • ►  April (30)
    • ▼  March (48)
      • Speed with a Catch
      • Apple Packaging
      • 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
      • 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
      • 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
      • Debugging Part 2
      • Debugging
      • March 17th
      • New iPod Shuffles
      • Review Silliness
      • Tough Love from 37Signals
      • Brutal Honesty from Owen Goss
      • Five Fingers Bundle
      • Yes, Yes You Can.
      • Becoming Indie
      • Geeking Out (including my Trip to the Mothership)
      • Bigger version of video:
      • Video of the Particle Generator in Action
      • At Last, Particle Generator
      • UIImage and NSCoding
      • 360ing
      • Publicity
      • Updated SQLPO Presentation
      • SQLitePersistentObjects Presentation
    • ►  February (26)
    • ►  January (23)
  • ►  2008 (163)
    • ►  December (46)
    • ►  November (25)
    • ►  October (44)
    • ►  September (2)
    • ►  August (5)
    • ►  July (2)
    • ►  June (9)
    • ►  May (2)
    • ►  April (11)
    • ►  March (17)
Powered by Blogger.

About Me

Unknown
View my complete profile