reed randolph marc hastings objective-c cocoa

objective-c - hastings - marc randolph



+ inicializar llamado más de una vez (3)

Tengo un método +initialize que se llama varias veces, y no entiendo por qué.

De acuerdo con la documentación, se llamará una vez para cada clase (y subclases también),

Este es el código que estoy usando:

@interface MyClass : NSObject @end static NSArray *myStaticArray; @implementation MyClass + (void)initialize { myStaticArray = [NSArray array]; } @end

(obviamente hay otro código, pero esa es la parte relevante).

No hay subclases de MyClass . No hace nada elegante. El + initialize se llama una vez, cuando se lanza mi aplicación (el delegado de NSApplication le dice que complete myStaticArray con datos del disco). Y luego + inicializar se llama por segunda vez, la primera vez que un usuario selecciona un elemento de menú relacionado con esta clase.

Simplemente agregué dispatch_once() alrededor de mi código de initialize y esto, obviamente, soluciona mi problema. Pero no entiendo lo que está pasando? ¿Por qué se llama más de una vez cuando no hay subclases?

Esta es la traza de la pila la primera vez que se llama + initialize:

+[MyClass initialize] _class_initialize objc_msgSend -[MyAppDelegate applicationDidBecomeActive:] _CFXNotificationPost NSApplicationMain main start

Y aquí está la segunda llamada:

+[MyClass initialize] _class_initialize NSApplicationMain main start

Como puede ver, mi código no parece activar la segunda llamada para + inicializar (nada en el seguimiento de la pila). Ocurre inmediatamente después de mostrar una ventana que presenta los contenidos de la matriz estática borrada por +initialize (la ventana muestra el contenido de la matriz, pero inmediatamente después la matriz está vacía).


+initialize se llama para cada clase en la cadena de herencia, por lo que si inicializa dos clases que comparten la misma superclase (o una superclase y una de sus subclases), el método de superclase +initialize se llamará dos veces.

¿Podría ser esa la razón?


+initialize se enviará a cada clase la primera vez que se haga referencia (por mensaje), incluidas las clases creadas dinámicamente. No hay protección en el tiempo de ejecución contra disparar la ejecución varias veces. Si se inicializa una subclase, pero no implementa +initialize , lo que sea que esté arriba de la cadena se llamará de nuevo.

De forma ortogonal, el KVO automático se implementa creando subclases derivadas dinámicamente de la clase de la instancia observada. Esa subclase es +initialize d como cualquier otra clase, desencadenando así múltiples ejecuciones de la clase padre +initialize .

El tiempo de ejecución podría tomar medidas para protegerse de esto. Sin embargo, dado que +initialize siempre se ha documentado como potencialmente ejecutable varias veces, esa complejidad adicional (es sorprendentemente compleja, dado que las clases KVO van y vienen con bastante frecuencia, potencialmente) no se considera que valga la pena el esfuerzo.

El patrón recomendado actual es:

+ (void) initialize { static dispatch_once_t once; dispatch_once(&once, ^{ ... one time initialization here ... }); }


1.Runtime llamado + método de inicialización en superclase antes de la subclase

2. si la subclase no tiene método, entonces llamará al método de inicialización de la clase padre.

3.Utilice siempre la forma crónica de inicializar el método + (vacío) inicializar {

if(self==[Car Class]){ //initialize here your static var } }

para una comprensión clara leer esta publicación + (vacío) inicializar