2009-03-25 10 views
29

He estado viendo un poco de código en todo similar al siguiente:virar un protocolo de NSObject a una implementación del protocolo

@protocol MyProtocol <NSObject> 
// write some methods. 
@end 

¿Hay alguna razón en particular por MyProtocol cumpla con el protocolo NSObject? No es que en lugar redundante en que si haces algo como:

id <MyProtocol> foo; // foo here conforms to NSObject AND MyProtocol? 

Simplemente curioso lo que es la lógica.

Respuesta

27

Estoy bastante seguro de que la razón por la que haría esto es agregar los miembros de NSObject (digamos como retener y liberar) a su protocolo. Técnicamente aún puede enviar esos mensajes de todos modos, pero obtendrá una advertencia de compilación sin él.

+2

"Técnicamente aún puede enviar esos mensajes de todos modos" No hay garantía de que el objeto comprenda esos mensajes, si no sabe que implementa el protocolo NSObject. – user102008

+0

Esa es una respuesta lo suficientemente sólida –

2

Nunca he hecho eso en mi código, pero podría ver la ventaja de ello. Si pasa un parámetro como id <SomeProtocol>, deberá volver a emitirlo si desea llamar a cualquiera de los métodos de NSObject en ese objeto.

22

También es muy útil cuando tiene protocolos que tienen @optional métodos (por ejemplo, los delegados de Objective-C 2.0 modernos a menudo usan esta técnica) Si no incluye el protocolo NSObject, recibirá advertencias cuando intente llame al respondsToSelector: en el objeto.

+5

Agradable. Esto es más relevante que la respuesta aceptada estos días, ya que ARC elimina la necesidad de que cualquier persona se preocupe por retener/liberar. –

31

Cuando se declara una variable como

id<MyProtocol> var; 

el compilador de Objective-C sólo conoce acerca de los métodos de MyProtocol y por lo tanto producirá una advertencia si intenta llamar a cualquiera de los métodos NSObject, como -retain/-release, en esa instancia. Por lo tanto, Cocoa define un protocolo NSObject que refleja los métodos de clase e instancia NSObject. Al declarar que MyProtocol implementa el protocolo NSObject, le da al compilador una pista de que todos los métodos NSObject serán implementados por una instancia que implemente MyProtocol.

¿Por qué es todo esto necesario? Objective-C permite que los objetos desciendan desde cualquier clase de raíz. En Cocoa, NSObject es la clase raíz más común, pero no la única. NSProxy es también una clase raíz, por ejemplo. Por lo tanto, una instancia del tipo id no necesariamente heredan los métodos NSObject.

+1

¿Por qué no podría simplemente hacer "NSObject * variable"? Entonces sabrá que se deriva de NSObject pero también cumple con Protocol, luego el compilador no se quejará de retener y lanzar. – dreamlax

+0

Praticamente, esto está bien (como está lanzando a (NSObject *) antes de usar cualquier método @protocol (NSObject). A menos que, por supuesto, la instancia no sea, de hecho, un NSObject. Más importante aún, aclara que MyProtocol implementa el protocolo NSObject la intención del protocolo. –

+3

Si su protocolo no se ajusta a NSObject, me parece preferible usar 'id ' en su lugar.Una razón es que el tipado dinámico con 'id' le permite llamar a cualquier método para el que el compilador pueda encontrar una declaración (sin una advertencia), en lugar de simplemente métodos heredados de NSObject o declarados en su protocolo. Esto puede ser peligroso e increíblemente útil, dependiendo de si está haciendo suposiciones seguras. :-) –

2

Si utiliza alguno de los métodos de protocolo NSObject como retener, liberar, clase, nombre de clase, el compilador le dará advertencias a menos que su Protocolo también incluya el protocolo NSObject.

Cuestiones relacionadas