As a reminder, a protocol is a list of methods that’s been given a name. The
NSCopying protocol contains a single method
copyWithZone:, while the
NSCoding protocol contains
initWithCoder:. You adopt a protocol by adding the protocol name in angled brackets after the class you’re inheriting from:
@interface BNRGroovyness : NSObject <NSCoding>
@interface says that “
BNRGroovyness inherits (is-a)
NSObject, and so can be used anywhere an
NSObject can be used. And also, it promises to implement the required methods in the
NSCoding protocol.” The compiler will check your work to make sure you actually implement them. Of course, you don’t have to implement optional methods in the protocol unless you really want to.
Like many programming constructs, protocols are primarily a communication mechanism. They communicate to the compiler that these objects really can receive a particular set of messages. They also communicate to the reader of the code that this class has some higher-level semantics. “This class conforms to
NSCoding, therefore I can encode and decode its objects into a data archive” or “Oh! This class conforms to
UITableViewDataSource! I can use its objects to power a table view.” Xcode can also use protocol adoption to expand the list of autocomplete options, making it easier to correctly spell the names of the methods you’d be implementing.
Protocols allow for a kind of multiple inheritance in Objective-C. You don’t really inherit code from multiple classes, but you can inherit multiple contracts, stating that you’ll obey those contracts. If you’ve used Java, they’re just like Java interfaces, which interestingly enough were inspired by Objective-C protocols. So when you’re adopting multiple protocols, all the code is implemented in your class or comes via the single-inheritance chain.
Protocols come into their own when you’re handing an object to another object for it to do work. If you’re giving an object to an
NSKeyedArchiver, that object needs to support
NSCoding so that the archiver can serialize the object. If you’re giving an object to a
UITableView, it needs to support
UITableViewDataSource so that it can feed the table. This helps move some of the correctness tests from run-time (“oops, this object doesn’t implement
-encodeWithCoder: . Time to crash!”) to compile time (
"warning: sending 'BNRGroovyness *' to parameter of incompatible type: id<NSCoding>")
One very popular use for making your own protocols is setting up a delegate relationship between objects. Come back next time for details.