Differences between Java interfaces and Objective-C protocols?

I know Java, and now I'm learning Objective-C. What exactly are the differences between Java interfaces and Objective-C protocols?


First off, a little historical perspective on the topic, from one of the creators of Java. Next, Wikipedia has a moderately helpful section on Objective-C protocols. In particular, understand that Objective-C supports both formal protocols (which are explicitly declared with the @protocol keyword, the equivalent of a Java interface) and informal protocols (just one or more methods implemented by a class, which can be discovered via reflection).

If you adopt a formal protocol (Objective-C terminology for "implement an interface") the compiler will emit warnings for unimplemented methods, just as you would expect in Java. Unlike Java (as skaffman mentioned), if an Objective-C class implements the methods contained in a formal protocol, it is said to "conform" to that protocol, even if its interface doesn't explicitly adopt it. You can test protocol conformance in code (using -conformsToProtocol:) like this:

if ([myObject conformsToProtocol:@protocol(MyProtocol)]) {
    ...
}

NOTE: Apple's documentation states:

"This method determines conformance solely on the basis of the formal declarations in header files, as illustrated above. It doesn’t check to see whether the methods declared in the protocol are actually implemented—that’s the programmer’s responsibility."

As of Objective-C 2.0 (in OS X 10.5 "Leopard" and iOS), formal protocols can now define optional methods, and a class conforms to a protocol as long as it implements all the required methods. You can use the @required (default) and @optional keywords to toggle whether the method declarations that follow must or may be implemented to conform to the protocol. (See the section of Apple's Objective-C 2.0 Programming Language guide that discusses optional protocol methods.)

Optional protocol methods open up a lot of flexibility to developers, particularly for implementing delegates and listeners. Instead of extending something like a MouseInputAdapter (which can be annoying, since Java is also single-inheritance) or implementing a lot of pointless, empty methods, you can adopt a protocol and implement only the optional methods you care about. With this pattern, the caller checks whether the method is implemented before invoking it (using -respondsToSelector) like so:

if ([myObject respondsToSelector:@selector(fillArray:withObject:)]) {
    [myObject fillArray:anArray withObject:foo];
    ...
}

If the overhead of reflection becomes a problem, you can always cache the boolean result for reuse, but resist the urge to optimize prematurely. :-)


They are almost identical. However the one thing that has caught me out, is that unless you explicitly declare that an objective C protocol also implements NSObject, references to that protocol don't get access to the methods that NSObject declares (without a compiler warning anyway). With java you can have a reference to an interface, and still call toString() etc on it.

eg

Objective C:

@protocol MyProtocol
// Protocol definition
@end

id <MyProtocol> myProtocol;

 [myProtocol retain] // Compiler warning

Java:

public interface MyInterface {
// interface definition
}

MyInterface myInterface;

myInterface.toString();  // Works fine.

Objective C (fixed):

@protocol MyProtocol <NSObject>
// Protocol definition
@end

id <MyProtocol> myProtocol;

[myProtocol retain] // No Warning