¿Diferencias entre interfaces Java y protocolos Objective-C?

93

Sé Java y ahora estoy aprendiendo Objective-C. ¿Cuáles son exactamente las diferencias entre las interfaces Java y los protocolos Objective-C?

Arne Evertsson
fuente

Respuestas:

82

Primero, una pequeña perspectiva histórica sobre el tema , de uno de los creadores de Java. A continuación, Wikipedia tiene una sección moderadamente útil sobre los protocolos Objective-C . En particular, comprenda que Objective-C admite tanto protocolos formales (que se declaran explícitamente con la @protocolpalabra clave, el equivalente de una interfaz Java) como protocolos informales (solo uno o más métodos implementados por una clase, que se pueden descubrir mediante la reflexión).

Si adopta un protocolo formal (terminología de Objective-C para "implementar una interfaz"), el compilador emitirá advertencias para los métodos no implementados, tal como es de esperar en Java. A diferencia de Java (como mencionó skaffman ), si una clase Objective-C implementa los métodos contenidos en un protocolo formal, se dice que se "ajusta" a ese protocolo, incluso si su interfaz no lo adopta explícitamente.Puede probar la conformidad del protocolo en el código (usando -conformsToProtocol :) así:

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

NOTA: la documentación de Apple dice:

"Este método determina la conformidad únicamente sobre la base de las declaraciones formales en los archivos de encabezado, como se ilustra arriba. No verifica si los métodos declarados en el protocolo están realmente implementados; eso es responsabilidad del programador".

A partir de Objective-C 2.0 (en OS X 10.5 "Leopard" e iOS), los protocolos formales ahora pueden definir métodos opcionales y una clase se ajusta a un protocolo siempre que implemente todos los métodos requeridos. Puede usar las palabras clave @required(predeterminadas) y @optionalpara alternar si las declaraciones de método que siguen deben o pueden implementarse para ajustarse al protocolo. (Consulte la sección de la guía del lenguaje de programación Objective-C 2.0 de Apple que analiza los métodos de protocolo opcionales ).

Los métodos de protocolo opcionales brindan mucha flexibilidad a los desarrolladores, particularmente para implementar delegados y oyentes . En lugar de extender algo como MouseInputAdapter (que puede ser molesto, ya que Java también es de herencia única) o implementar muchos métodos vacíos e inútiles, puede adoptar un protocolo e implementar solo los métodos opcionales que le interesan. Con este patrón, la persona que llama verifica si el método está implementado antes de invocarlo (usando -respondsToSelector ) así:

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

Si la sobrecarga de reflexión se convierte en un problema, siempre puede almacenar en caché el resultado booleano para su reutilización , pero resista la tentación de optimizar prematuramente. :-)

Quinn Taylor
fuente
4
"Si adopta un protocolo formal (terminología de Objective-C para" implementar una interfaz "), el compilador emitirá advertencias para los métodos no implementados, tal como es de esperar en Java". Java emitiría un error en este caso, no una advertencia.
Raffi Khatchadourian
3
"si una clase Objective-C implementa los métodos contenidos en un protocolo formal, se dice que" se ajusta "a ese protocolo, incluso si su interfaz no lo adopta explícitamente. Puede probar la conformidad del protocolo en el código (usando -conformsToProtocol: ) como este "Esto es FALSO. -conformsToProtocol:solo devolverá YES si la clase adopta explícitamente el protocolo. ¿Lo has probado siquiera?
user102008
2
Tiene razón, de -conformsToProtocol:hecho requiere que la clase (o un antepasado) declare formalmente que adopta el protocolo. No estoy seguro de cómo me equivoqué, ¡gracias por la corrección!
Quinn Taylor
18

Son casi idénticos. Sin embargo, lo único que me ha sorprendido es que, a menos que declare explícitamente que un protocolo C objetivo también implementa NSObject, las referencias a ese protocolo no tienen acceso a los métodos que declara NSObject (sin una advertencia del compilador de todos modos). Con java puede tener una referencia a una interfaz y aún llamar a toString (), etc. en ella.

p.ej

C objetivo:

@protocol MyProtocol
// Protocol definition
@end

id <MyProtocol> myProtocol;

 [myProtocol retain] // Compiler warning

Java:

public interface MyInterface {
// interface definition
}

MyInterface myInterface;

myInterface.toString();  // Works fine.

Objetivo C (fijo):

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

id <MyProtocol> myProtocol;

[myProtocol retain] // No Warning
Tom Jefferys
fuente
25
Esto se debe a que id y NSObject no son lo mismo . En Java, el objeto raíz es Object. En Objective-C, NSObject es un objeto raíz, pero no el objeto raíz. Si desea acceder a todos los métodos de NSObject (métodos de clase y protocolos), indique esto explícitamente: NSObject <MyProtocol> myProtocol; en lugar de: id <MyProtocol> ... Cuando usas id estás diciendo: no me importa el objeto, solo el protocolo, que en tu caso no es cierto.
Jason Coco