views:

1255

answers:

3

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

+2  A: 

They're pretty similar, although I think a class in Objective C can be considered to "implement" the protocol even if it doesn't explicitly declare that it does.

For example, in Java say you have interface X, which declares method m. If you also have a class which has a method with the same signature of m, the class doesn't actually implement interface X unless it specifically declares it. In Objective-C, this explicit declaration isn't necessary.

I think....

skaffman
That's right, Objective-C has pretty loose typing so if you happen to know that object A has method M, then you can call M on A even if the class declaration doesn't mention M -- directly or indirectly via a protocol. That's not specific to protocols. To the original question: In fact ObjC protocols are often described in terms of "this is what Java calls interfaces".
harms
+2  A: 

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 MyInteface {
// interface definition
}

MyInterface myInterface;

myInterface.toString();  // Works fine.

Objective C (fixed):

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

id <MyProtocol> myProtocol;

[myProtocol retain] // No Warning
Tom
This is because id and NSObject *are not the same*. In Java, the root object is Object. In Objective-C, NSObject is a root object, but not *the* root object. If you want access to all NSObject methods (class methods as well as protocols), state this explicitly: NSObject<MyProtocol> myProtocol; instead of: id<MyProtocol>... When you use id you're saying: I don't care about the object, *only* the protocol, which in your case is not true.
Jason Coco
+7  A: 

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)]) {
    ...
}

With the advent of Objective-C 2.0 (in OS X 10.5 "Leopard" and iPhone OS), formal protocols can now define optional methods, and a class conforms to a protocol as long as it implements all the required methods. You use @required 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. :-)

Quinn Taylor