Unterschiede zwischen Java-Schnittstellen und Objective-C-Protokollen?

93

Ich kenne Java und lerne jetzt Objective-C. Was genau sind die Unterschiede zwischen Java-Schnittstellen und Objective-C-Protokollen?

Arne Evertsson
quelle

Antworten:

82

Zunächst eine kleine historische Perspektive zu diesem Thema von einem der Entwickler von Java. Als nächstes hat Wikipedia einen mäßig hilfreichen Abschnitt über Objective-C-Protokolle . Beachten Sie insbesondere, dass Objective-C sowohl formale Protokolle (die explizit mit dem @protocolSchlüsselwort deklariert werden, das einer Java-Schnittstelle entspricht) als auch informelle Protokolle (nur eine oder mehrere von einer Klasse implementierte Methoden, die durch Reflektion ermittelt werden können) unterstützt.

Wenn Sie ein formales Protokoll verwenden (Objective-C-Terminologie für "Implementieren einer Schnittstelle"), gibt der Compiler Warnungen für nicht implementierte Methoden aus, wie Sie es in Java erwarten würden. Im Gegensatz zu Java (wie von Skaffman erwähnt) wird eine Objective-C-Klasse, wenn sie die in einem formalen Protokoll enthaltenen Methoden implementiert, als "konform" mit diesem Protokoll bezeichnet, auch wenn ihre Schnittstelle es nicht explizit übernimmt.Sie können die Protokollkonformität im Code (mit -conformsToProtocol :) wie folgt testen :

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

HINWEIS: In der Dokumentation von Apple heißt es:

"Diese Methode bestimmt die Konformität ausschließlich auf der Grundlage der formalen Deklarationen in Header-Dateien, wie oben dargestellt. Sie prüft nicht, ob die im Protokoll deklarierten Methoden tatsächlich implementiert sind - das liegt in der Verantwortung des Programmierers."

Ab Objective-C 2.0 (in OS X 10.5 "Leopard" und iOS) können formale Protokolle jetzt optionale Methoden definieren , und eine Klasse entspricht einem Protokoll, solange alle erforderlichen Methoden implementiert sind. Mit den Schlüsselwörtern @required(Standard) und können Sie @optionalumschalten, ob die folgenden Methodendeklarationen implementiert werden müssen oder dürfen , um dem Protokoll zu entsprechen. (Weitere Informationen finden Sie im Abschnitt des Objective-C 2.0-Programmiersprachenhandbuchs von Apple , in dem optionale Protokollmethoden erläutert werden .)

Optionale Protokollmethoden eröffnen Entwicklern viel Flexibilität, insbesondere bei der Implementierung von Delegaten und Listenern . Anstatt so etwas wie einen MouseInputAdapter zu erweitern (was ärgerlich sein kann, da Java auch eine Einzelvererbung ist) oder viele sinnlose, leere Methoden zu implementieren, können Sie ein Protokoll übernehmen und nur die optionalen Methoden implementieren, die Sie interessieren. Mit diesem Muster prüft der Aufrufer, ob die Methode implementiert ist, bevor er sie aufruft (mit -respondsToSelector ).

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

Wenn der Overhead der Reflexion zu einem Problem wird, können Sie das boolesche Ergebnis jederzeit zur Wiederverwendung zwischenspeichern , aber dem Drang widerstehen, vorzeitig zu optimieren. :-)

Quinn Taylor
quelle
4
"Wenn Sie ein formales Protokoll verwenden (Objective-C-Terminologie für" Implementieren einer Schnittstelle "), gibt der Compiler Warnungen für nicht implementierte Methoden aus, wie Sie es in Java erwarten würden." Java würde in diesem Fall einen Fehler ausgeben, keine Warnung.
Raffi Khatchadourian
3
"Wenn eine Objective-C-Klasse die in einem formalen Protokoll enthaltenen Methoden implementiert, wird sie als" konform "mit diesem Protokoll bezeichnet, auch wenn ihre Schnittstelle es nicht explizit übernimmt. Sie können die Protokollkonformität im Code testen (mithilfe von -conformsToProtocol: ) so "Das ist FALSCH. -conformsToProtocol:gibt nur JA zurück, wenn die Klasse das Protokoll explizit übernimmt. Hast du es überhaupt versucht?
user102008
2
Sie haben Recht, -conformsToProtocol:erfordert in der Tat, dass die Klasse (oder ein Vorfahr) offiziell erklärt, dass sie das Protokoll übernimmt. Ich bin mir nicht sicher, wie ich das falsch verstanden habe, danke für die Korrektur!
Quinn Taylor
18

Sie sind fast identisch. Was mich jedoch aufgefallen ist, ist, dass Verweise auf dieses Protokoll keinen Zugriff auf die von NSObject deklarierten Methoden erhalten, sofern Sie nicht ausdrücklich erklären, dass ein objektives C-Protokoll auch NSObject implementiert (ohnehin ohne Compiler-Warnung). Mit Java können Sie einen Verweis auf eine Schnittstelle haben und trotzdem toString () usw. aufrufen.

z.B

Ziel 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.

Ziel C (fest):

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

id <MyProtocol> myProtocol;

[myProtocol retain] // No Warning
Tom Jefferys
quelle
25
Dies liegt daran, dass id und NSObject nicht identisch sind . In Java ist das Stammobjekt Objekt. In Objective-C ist NSObject ein Stammobjekt, jedoch nicht das Stammobjekt . Wenn Sie auf alle NSObject-Methoden (Klassenmethoden sowie Protokolle) zugreifen möchten, geben Sie dies explizit an: NSObject <MyProtocol> myProtocol; statt: id <MyProtocol> ... Wenn Sie id verwenden, sagen Sie: Das Objekt interessiert mich nicht, nur das Protokoll, was in Ihrem Fall nicht der Fall ist.
Jason Coco