El load
mensaje
El tiempo de ejecución envía el load
mensaje a cada objeto de clase, muy poco después de que el objeto de clase se cargue en el espacio de direcciones del proceso. Para las clases que forman parte del archivo ejecutable del programa, el tiempo de ejecución envía el load
mensaje muy temprano en la vida útil del proceso. Para las clases que están en una biblioteca compartida (cargada dinámicamente), el tiempo de ejecución envía el mensaje de carga justo después de que la biblioteca compartida se cargue en el espacio de direcciones del proceso.
Además, el tiempo de ejecución solo envía load
a un objeto de clase si ese objeto de clase en sí mismo implementa el load
método. Ejemplo:
@interface Superclass : NSObject
@end
@interface Subclass : Superclass
@end
@implementation Superclass
+ (void)load {
NSLog(@"in Superclass load");
}
@end
@implementation Subclass
// ... load not implemented in this class
@end
El tiempo de ejecución envía el load
mensaje al Superclass
objeto de clase. No , no enviar el load
mensaje al Subclass
objeto de clase, a pesar de que Subclass
hereda el método de Superclass
.
El tiempo de ejecución envía el load
mensaje a un objeto de clase después de haber enviado el load
mensaje a todos los objetos de superclase de la clase (si esos objetos de superclase se implementan load
) y todos los objetos de clase en las bibliotecas compartidas a las que se vincula. Pero aún no sabe qué otras clases de su propio ejecutable han recibido load
.
Cada clase que su proceso carga en su espacio de direcciones recibirá un load
mensaje, si implementa el load
método, independientemente de si su proceso hace algún otro uso de la clase.
Puede ver cómo el tiempo de ejecución busca el load
método como un caso especial en _class_getLoadMethod
of objc-runtime-new.mm
y lo llama directamente desde call_class_loads
adentro objc-loadmethod.mm
.
El tiempo de ejecución también ejecuta el load
método de cada categoría que carga, incluso si se implementan varias categorías en la misma clase load
. Esto es inusual. Normalmente, si dos categorías definen el mismo método en la misma clase, uno de los métodos "ganará" y se usará, y el otro método nunca será llamado.
El initialize
método
El tiempo de ejecución llama al initialize
método en un objeto de clase justo antes de enviar el primer mensaje (distinto de load
o initialize
) al objeto de clase o cualquier instancia de la clase. Este mensaje se envía utilizando el mecanismo normal, por lo que si su clase no se implementa initialize
, pero hereda de una clase que lo hace, entonces su clase usará su superclase initialize
. El tiempo de ejecución enviará initialize
primero a todas las superclases de una clase (si las superclases aún no se han enviado initialize
).
Ejemplo:
@interface Superclass : NSObject
@end
@interface Subclass : Superclass
@end
@implementation Superclass
+ (void)initialize {
NSLog(@"in Superclass initialize; self = %@", self);
}
@end
@implementation Subclass
// ... initialize not implemented in this class
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
Subclass *object = [[Subclass alloc] init];
}
return 0;
}
Este programa imprime dos líneas de salida:
2012-11-10 16:18:38.984 testApp[7498:c07] in Superclass initialize; self = Superclass
2012-11-10 16:18:38.987 testApp[7498:c07] in Superclass initialize; self = Subclass
Dado que el sistema envía el initialize
método con pereza, una clase no recibirá el mensaje a menos que su programa realmente envíe mensajes a la clase (o una subclase, o instancias de la clase o subclases). Y para cuando lo reciba initialize
, todas las clases en su proceso ya deberían haber recibido load
(si corresponde).
La forma canónica de implementar initialize
es esta:
@implementation Someclass
+ (void)initialize {
if (self == [Someclass class]) {
// do whatever
}
}
El objetivo de este patrón es evitar Someclass
reinicializarse cuando tiene una subclase que no se implementa initialize
.
El motor de ejecución envía el initialize
mensaje en la _class_initialize
función en formato objc-initialize.mm
. Puede ver que utiliza objc_msgSend
para enviarlo, que es la función normal de envío de mensajes.
Otras lecturas
Consulte las preguntas y respuestas del viernes de Mike Ash sobre este tema.
+load
se envía por separado para categorías; es decir, cada categoría de una clase puede contener su propio+load
método.