2011-01-02 11 views
11

Tengo una subclase de UIView que está instanciada en un archivo XIB. Necesito que haga algo de inicialización (configura algunas variables y crea una subvista).¿Dónde inicializar UIView personalizado, instanciado en Interface Builder?

Sin embargo, no siempre crea una instancia de esta vista a través de Interface Builder. Lo hago programáticamente también. En ambos casos, la inicialización debe ser la misma.

Mi inicializador designado es initWithValues:.

La pregunta es; ¿dónde realizo la inicialización?

Desde que tengo que llevarla a cabo en 2 lugares diferentes, me di cuenta que necesito para refactorizar en un initialize método separado (o algo así), y llamarlo desde initWithValues:.

Pero cuando se carga desde IB, se llaman tanto initWithCoder: como awakeFromNib. ¿De qué método debo llamar al initialize? ¿O debo llamar al initWithValues: desde initWithCoder: y no hacer nada en awakeFromNib?

Respuesta

16

Debe usar initWithFrame: al inicializar las vistas (ya que es el inicializador designado). Por lo tanto, si tiene initWithValues:, asegúrese de llamar al initWithFrame: desde allí.

Algo como esto debería funcionar para inicializar:;)

- (void)initialize{ 
    //init your ivars here 
} 

- (id)initWithCoder:(NSCoder *)aCoder{ 
    if(self = [super initWithCoder:aCoder]){ 
     [self initialize]; 
    } 
    return self; 
} 

- (id)initWithFrame:(CGRect)rect{ 
    if(self = [super initWithFrame:rect]){ 
     [self initialize]; 
    } 
    return self; 
} 

que iba a añadir una explicación más detallada, pero la respuesta de mplappert es lo suficientemente clara. Use awakeFromNib si es necesario.

+0

¿No es 'incorrecto' llamar a dos inicializadores diferentes de la superclase? ¿No debería llamar al inicializador designado de mi subclase ('initWithValues:') de 'initWithCoder:'? – Rits

+0

¿No es 'incorrecto' llamar a dos inicializadores diferentes de la superclase? → No porque solo se llamará a uno de ellos. ¿No debería llamar al iniciador designado de mi subclase (initWithValues ​​:) desde initWithCoder :? → parcialmente sí. initWithCoder: espera que desarchive el objeto. Es por eso que llamamos [super initWithCoder]; al hacer esto, la vista se inicializará. Ahora solo necesitas iniciar otros ivars, algo que supongo que estás haciendo dentro del método de inicialización. – nacho4d

10

Eso depende de lo que necesite inicializar. Tan pronto como se llame a awakeFromNib, se establecen todos los puntos de venta y las conexiones de acción de su vista, que no es el caso en initWithCoder:. Entonces, si necesita confiar en esas conexiones, use awakeFromNib. De lo contrario, puede realizar de manera segura toda su inicialización en initWithCoder:.

1

Desafortunadamente, las respuestas anteriores no tienen en cuenta lo siguiente: - (void) awakeAfterUsingCoder - y el hecho de que el codificador lo haya llamado después (una vez para cada vista Xib). awakeFromNib sufre de la misma suerte, me he dado cuenta. (La razón por la que encontré esto)

Otro problema de inicialización es que initWithCoder e initWithFrame se pueden evitar para las vistas personalizadas. Y si se llaman, la carga diferida (aunque no es tan importante en las vistas), significa que "podría" modificar los valores. Creo que lo hice en initWithCoder, pero si luego inicializas los valores en awakeFromNib, se deshace al menos una vez.

He ido tan lejos como para:

- (void) awakeFromNib (or didMoveToSuperView); 
{ 
    BOOL called = NO; 
    if(!called) 
    { 
    called = YES; 
    } 

} 

Otro método que utilizo es simplemente llamar a la inicialización necesaria, a continuación, llamar a mi propia clase o inicializador-superclase específica.

Yo también estoy buscando un lugar confiable de una sola vez en el que pueda confiar. Hasta entonces, espero que mis dolores de cabeza salven a la siguiente persona una hora más o menos.

Steve

+1

Creo que 'didMoveToSuperView' es un muy buen lugar para hacerlo para la mayoría de las vistas: cubrirá la creación de instancias manual y NIB sin múltiples métodos init. No es tan bueno si necesitas la vista para realizar cualquier lógica antes de que aparezca en la pantalla, pero si lo haces, entonces probablemente haya algo mal ... –

+1

Sí, en realidad es a lo que recurrí eventualmente, pero incluso tiene un defecto . Cuando se elimina y su supervisión es nula, también se llama. No es bueno para la reorganización, así que agregué una prueba para "si no tengo supervisión" similar a la prueba llamada. ¡Cuidado con eso! Gracias por la respuesta: D –

+0

Buen punto. stackoverflow demuestra su utilidad una vez más! –

Cuestiones relacionadas