2011-10-26 16 views
36

Sé que cuando queremos crear un objeto de valor desconocido usamos id. Sin embargo, tengo curiosidad por saber por qué Apple eligió el id, que decide su valor durante el tiempo de ejecución, cuando cada objeto es una subclase de NSObject. Entonces, en lugar de id delegate podríamos haber usado NSObject *delegate ¿Alguien sabe por qué? Gracias.¿Por qué usar id cuando podemos usar NSObject?

+1

NSProxy es otra clase raíz que suministra el cacao. –

+0

NSObject contiene isa puntero, id no. Eche un vistazo a http://stackoverflow.com/a/19634973/944634 –

+0

¿qué lol? id es un puntero isa http://stackoverflow.com/questions/1990695/in-cocoa-how-is-the-id-type-defined – TheAmateurProgrammer

Respuesta

39

id borra el tipo y es equivalente a decir "este objeto responde a cualquier selector visible para la traducción". por supuesto, es su responsabilidad de asegurarse de que su programa sea correcto cuando borre los tipos (y también cuando los haya encasillado).

Si el tipo eran NSObject, entonces el compilador diría "NSObject puede no responder a selector de" si el selector no fue declarado en la interfaz del NSObject o los protocolos que adopta. En ese caso, también puede agregar un tipocast para convertirlo al tipo que espera.

Con tipos estrictos/correctos, el compilador puede entrar en acción y ayudarte, lo que es genial porque ObjC es un lenguaje muy dinámico.

id es particularmente útil al utilizar (o crear) tipos de colecciones. Agregar un objeto no sería un problema a menos que haya definido un nuevo tipo de raíz (no hereda de NSObject). Obtener un valor de la colección requeriría un encasillado si lo usáramos como algo más que nuestra clase base (NSObject).

Objective-C no admite genéricos: no puede, por ejemplo, declarar NSArray de NSString s. Puede llenar un NSArray con NSString sy pasarlo a través de id para un estilo escrito más natural cuando no se conserva la seguridad del tipo (a la genéricos).

Por lo tanto, ampliemos esto con un código real.

Ejemplo A

NSString * string = [array objectAtIndex:0]; // << trust me (via id) 
return [string length]; 
-or- 
return [[array objectAtIndex:0] length]; // << trust me (via id) 

Ejemplo B

Y ahora vamos a decir id no está disponible y que soluciona todas nuestras advertencias del compilador porque es lo que hay que hacer:

NSString * string = (NSString*)[array objectAtIndex:0]; // << typecast == trust me 
return [string length]; 
-or- 
return [(NSString*)[array objectAtIndex:0] length]; // << typecast == trust me 

id no decide su valor en tiempo de ejecución, ni tampoco ningún objeto NSO. Los objetos ObjC no realizan promociones implícitas, simplemente lanzan el puntero sin una promoción formal.

relacionados con su ejemplo, que en realidad declaro mis delegados y parámetros como NSObjects con los protocolos:

NSObject<MONShapeDelegate>* delegate; 
+0

Puede diferir en otros compiladores que los que yo uso, pero hasta donde yo sé, si declaras un tipo como NSObject , el compilador supondrá que el objeto implementa todos los métodos de SomeProtocol, incluso los opcionales. – Aberrant

+0

@Aberrant si un método de delegado es opcional, corresponde al * que llama * verificar que el objeto responde al selector. – justin

+0

Lo sé, es por eso que dije que el compilador supone que están implementados. Si no fuera así, los opcionales siempre causarían advertencias, ya que el compilador no puede estar seguro de si los objetos responderán en tiempo de ejecución. – Aberrant

2

cada objeto es una subclase de NSObject

Eso no es correcto. Podría hacer un objeto que se extienda desde la nada como una clase de raíz.

Esa es quizás la razón por la que se introdujo la identificación.

11

cada objeto es una subclase de NSObject

Esa es una declaración incorrecta. Puede crear objetos que no hereden de NSObject. no es realmente recomendable, pero es posible.

NSProxy es un ejemplo: no hereda de NSObject.

+3

¡Esto es solo una copia de mi respuesta! –

+1

Lo siento:/Lo escribí cuando no había respuestas, me pegaste al golpe ... sin resentimientos y sin ninguna necesidad de un voto negativo ... Además, no mencionaste 'NSProxy' ... – Jasarien

+1

Si es una pila y esta respuesta está en la parte inferior, entonces @Jasarien respondió en primer lugar;) – beryllium

3
typedef struct objc_object { 
    Class isa; 
} *id; 

Arriba está la definición real de id en lenguaje Objective-C. El sistema de tiempo de ejecución Objective-C está construido alrededor de id y Class. Nada tiene que ver con NSObject o super clase común.

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW3

El NSObject Clase

NSObject es una clase raíz, y por lo tanto no tiene una superclase. Define el marco básico para objetos Objective-C e interacciones de objetos. Se imparte a las clases y las instancias de clases que heredan de la capacidad de comportarse como objetos y cooperar con el sistema de tiempo de ejecución .

Una clase que no necesita heredar ningún comportamiento especial de otra clase debe, sin embargo, convertirse en una subclase de la clase NSObject. Las instancias de la clase deben, como mínimo, tener la capacidad de comportarse como objetos Objective-C en tiempo de ejecución. Heredar esta capacidad de la clase NSObject es mucho más simple y mucho más confiable que reinventarlo en una nueva definición de clase.

pienso, esto es debido a que es un principio no CC++ (u otros lenguajes de escritura mucho más estrictas).