2011-10-24 23 views
9

Quiero saber por qué id es un puntero de referencia débil, cómo es capaz de manejar cualquier class puntero de tipo y en tiempo de ejecución, ¿cómo podemos detectar qué tipo de puntero de clase está asignado a id.¿Por qué ID es un puntero genérico?

Respuesta

16

¿Por qué id es un puntero de referencia débil?

id no es un puntero de referencia débil, al menos no en el sentido de propiedad de ARC. Si una referencia de tipo id a un objeto es débil o no depende de que la referencia haya sido declarada __weak (y variaciones) y que la clase del objeto sea realmente compatible con referencias débiles.

Sin embargo, usted podría decir que id proporciona débil escribiendo, aunque creo que la tipificación dinámica/pato es una descripción más precisa. Como una referencia tipada id no contiene información del tipo de clase en tiempo de compilación, el compilador no puede, por ejemplo, determinar si el objeto subyacente puede responder a un selector dado, lo que podría generar errores en el tiempo de ejecución.

¿Cómo es capaz de manejar cualquier puntero de clase?

Eso es parte de la definición de the Objective-C language. El compilador reconoce id como el supertipo de cada clase Objective-C, y trata id de manera diferente. Vea la respuesta a continuación también.

En tiempo de ejecución, ¿cómo podemos detectar qué tipo de puntero de clase se asigna a la identificación?

En el tiempo de ejecución Objective-C de Apple, los primeros bytes en la memoria asignados a un objeto deben apuntar a la clase de ese objeto. Puede ver esto referenciado en otro lugar como el puntero isa, y así es como el tiempo de ejecución de Apple descubre la clase de cada objeto . El tipo id se define para tener esta información también. De hecho, su único atributo es el puntero isa, lo que significa que todos los objetos Objectivo-C se ajustan a esta definición.

Si usted tiene una referencia id y desea descubrir la clase del objeto referenciado, se puede enviar -class:

id someObject; 

// Assign something to someObject 

// Log the corresponding class 
Class c = [someObject class]; 
NSLog(@"class = %@", c); 

// Test whether the object is of type NSString (or a subclass of NSString) 
if ([someObject isKindOfClass:[NSString class]]) { 
    NSLog(@"it's a string"); 
} 

Tagged pointers son una desviación notable de esta estructura, y (en parte) debido a ellos no se debe acceder directamente al puntero isa.

7

Es bueno tener un tipo de objeto genérico, por lo que puede definir tipos de colección que pueden contener cualquier tipo de objeto y otros servicios genéricos que funcionan con cualquier objeto sin saber qué tipo de objeto es.

No hay truco para hacer que ID funcione. En un nivel binario, todos los punteros son intercambiables. Simplemente representan una dirección de memoria como un valor numérico. Para que id acepte cualquier tipo de puntero, solo es necesario deshabilitar las reglas del compilador que normalmente requieren que los tipos de puntero coincidan.

Puede encontrar información acerca de la clase de una variable de tipo ID en este tipo de formas:

id theObject = // ... something 
Class theClass = [theObject class]; 
NSString *className = NSStringFromClass(theClass); 
NSClassDescription *classDescription = [NSClassDescription classDescriptionForClass:theClass]; 

Pero es rara vez es necesario hacer ese tipo de cosas en el código. Más a menudo, quiere probar si su variable de id es una instancia de una clase en particular, y si es así, transfiéralo a esa clase y comience a tratarlo como ese tipo.

if ([theObject isKindOfClass:[MySpecializedClass class]]) { 
    MySpecializedClass *specialObject = (MySpecializedClass *)theObject; 
    [specialObject doSomethingSpecial]; 
} 

Si se va a utilizar -class para averiguar la clase, pero volvió una clase que no sabe nada, entonces no hay nada especial que puede hacer con el objeto según la clase de todos modos. Por lo tanto, no hay ninguna razón para hacer nada más que verificar si coincide con las clases que conoce, y solo si tiene la intención de hacer un manejo especial para esas clases de todos modos.

A veces puede usar isMemberOfClass en lugar de isKindOfClass. Depende de si desea una coincidencia exacta o para incluir subclases.

3

Puede valer la pena echar un vistazo en el archivo de encabezado objc/objc.h para encontrar las partes internas de id.

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


typedef struct objc_selector *SEL;  
typedef id   (*IMP)(id, SEL, ...); 
Cuestiones relacionadas