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
¿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
.
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.
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, ...);
- 1. ¿Por qué es un puntero
- 2. ¿Por qué un puntero a un puntero es incompatible con un puntero a una matriz?
- 3. ¿Por qué java.util.Map.get (...) no es genérico?
- 4. ¿Qué es un puntero largo?
- 5. ¿Qué es un puntero sintético?
- 6. ¿Qué es un puntero desnudo?
- 7. ¿Por qué NSError necesita doble indirección? (puntero a un puntero)
- 8. ¿Por qué tener un puntero a un puntero (int ** a)?
- 9. ¿Por qué es tan grande un diccionario .net genérico
- 10. ¿Por qué un static_cast desde un puntero a base a un puntero a derivado es "inválido"?
- 11. ¿Por qué es la desreferenciación un puntero llamado desreferenciación?
- 12. ¿Por qué el puntero "this" es nulo en un delegado?
- 13. ¿Por qué Java no te dice qué puntero es nulo?
- 14. ¿Por qué 'fopen' devuelve un puntero NULL?
- 15. ¿Por qué el puntero "this" en C++ es un puntero y no una referencia?
- 16. ¿Qué es un puntero Singleton en C?
- 17. ¿Qué es exactamente un 'puntero alineado'?
- 18. ¿Qué es un ID Jsp bueno
- 19. Objetivo C: ¿qué es un "remitente (id)"?
- 20. ¿Por qué es genérico EventHandler <TArgs> tan infrautilizado?
- 21. ¿Por qué 'Código no es lo suficientemente genérico'?
- 22. ¿Cómo puedo declarar un puntero basado en un tipo genérico?
- 23. ¿Por qué existen las ID?
- 24. ¿Qué es un caso de uso para un constructor genérico?
- 25. No es posible: este puntero como argumento predeterminado. ¿Por qué?
- 26. ¿Por qué sizeof (param_array) es el tamaño del puntero?
- 27. ¿Qué es intptr_t, es un tipo para entero o puntero?
- 28. ¿Por qué no falla este elenco genérico?
- 29. ¿Qué es TKey y TValue en un diccionario genérico?
- 30. ¿Qué es exactamente un "tipo genérico abierto" en .NET?