Java Perspective: Cocoa Subclasses and Delegates
- Delegates Can Control Behavior
- Delegates Can Alter Appearance
- Subclassing Still Exists
- Categories, Avoiding Subclassing
- Conclusion
In the object oriented programming world, subclassing an object is the meat and potatoes of software development in that it is one of the most fundamental pieces of OOP. Being able to take a class and extend it to add your own flexibility is a powerful thing. This lends itself to code reuse and good coding practices.
Like all things in programming, this feature can be easily abused. If a developer decides during that subclassing to override a method/function in the parent object, he/she is responsible for properly handling all the functionality that the parent function handled. This can be as simple as calling the parent class's version of the method or can involve reimplementing that functionality. In either case, if the developer makes an error in their new implementation of the method, it can cause subtle errors in the application that are difficult to locate. Things that once worked in a consistent manner can change unpredictably.
Objective-C and Cocoa have taken a slightly different approach to the issues surrounding class subclassing. In many of the situations in which subclassing would normally be appropriate, Cocoa has a delegate.
Delegates Can Control Behavior
In the most basic sense, a delegate is akin to a listener in Java. A delegate is one class that is referenced by another. A class that has a delegate (often a GUI class) will call methods on the delegate to determine when and how to do certain things. For example, let's take a look at NSTableView from Cocoa's AppKit framework. In this class, it has several delegate methods—here is a sample of them:
- (void)tableView:(NSTableView *)tv shouldSelectRow:(int)row - (void)tableView:(NSTableView *)tv shouldSelectTableColumn:(NSTableColumn *)tc - (BOOL)tableView:(NSTableView *)tv shouldEditTableColumn:(NStableColumn *)tc row:(int)row - (void)tableViewSelectionDidChange:(NSNotification *)notification
In this sample, you can see that the delegate is responsible for which cells are editable and whether or not a row or column should be selected. In Java, this would be handled via subclassing either the JTable itself or its model. With Cocoa/Objective-C, a simple class is created and it is then set as the TableView's delegate.
As can also be seen by this sample of methods, it is possible to use one delegate to handle many different tables. Because a pointer to the table view is always passed into the method, it is possible to write a delegate to handle several tables or even all of the tables in an application!
Without having to subclass any of the GUI components, the components can be controlled with a small amount of code. This also makes working with Interface Builder much easier because you do not have to constantly set custom subclasses. Instead, you simply instantiate the delegate and Control-drag from the component to the delegate to set it—further reducing the amount of code needed in a Cocoa application.
It is important to note, that unlike Java's listener design, Objective-C objects can only have one delegate. In Java, it is quite possible to have 12 different objects listen to the events from one table, but there can be only one in Cocoa.