UIView personalizada desde la punta de la punta dentro de otra punta de UIViewController – Las IBOutlets son nulas

Estoy intentando crear una UIView personalizada que tenga references a sus propios IBOutlets. Entonces quiero poner esta UIView personalizada en otra punta.

Estoy haciendo algo de lógica adicional en el método awakeFromNib personalizado de awakeFromNib . Desafortunadamente, cuando bash acceder a los IBOutlets en awakeFromNib , son nulos.

Aquí está la configuration:

  1. Tengo una subclass CustomView , CustomView .
  2. Tengo un file .xib personalizado con tres subvenciones.
  3. En la otra punta (que pertenece al controller de vista), he arrastrado una UIView a la vista, y luego CustomView cambiado la class personalizada a CustomView .
  4. Intenté configurar la vista en la plumilla CustomView en IB a una CustomView class personalizada y conectar las IBOutlets a la vista, pero aún eran nulas.
  5. Intenté configurar el propietario del file en CustomView y conectar los IBOutlets al propietario del file, pero aún eran nulos.
  6. También intenté usar otra IBOutlet UIView *view y luego IBOutlet UIView *view eso como una subvista a awakeFromNib self en awakeFromNib pero que tampoco hizo nada.

Aquí está el código:

 // CustomView.h @interface CustomView : UIView @property (nonatomic, retain) IBOutlet UITextField *textField; @property (nonatomic, retain) IBOutlet UIView *subview1; @property (nonatomic, retain) IBOutlet UIView *subview2; // CustomView.m @implementation CustomView @synthesize textField, subview1, subview2; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { } return self; } - (void)awakeFromNib { [super awakeFromNib]; [self setup]; } - (void)setup { // Fails because self.textField is nil self.textField.text = @"foo"; } 

Terminé de usar los pasos en la edición más reciente aquí y funcionaron muy bien.

Utiliza una UIView simple como la vista de nivel superior en el xib .

A continuación, establece el propietario del file en la subclass personalizada ( CustomView ).

Finalmente, agrega una línea:

 [self addSubview:[[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0]]; 

en el bloque if (self != nil) tanto en initWithCoder como initWithFrame .

Voila! Los IBOutlets están conectados y listos para continuar después de la llamada. Realmente satisfecho con la solución, pero fue muy difícil de desenterrar.

Espero que esto ayude a cualquier otra persona.


EDITAR : actualicé el enlace a uno que no está muerto. Como nunca expliqué el código completo, esto es lo que se ve después de la modificación:

 - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { UIView *nib = [[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0]; [self addSubview:nib]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { UIView *nib = [[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0]; [self addSubview:nib]; } return self; } - (void)awakeFromNib { [super awakeFromNib]; [self setup]; } - (void)setup { // Doesn't fail because life is awesome self.textField.text = @"foo"; } 

Este patrón se ha vuelto tan común que realmente he creado una categoría en UIView llamada UIView+Nib , que implementa el siguiente método:

 + (UIView *)viewWithNibName:(NSString *)nibName owner:(id)owner { return [[[UINib nibWithNibName:nibName bundle:nil] instantiateWithOwner:owner options:nil] objectAtIndex:0]; } 

Por lo tanto, el código anterior se puede simplificar para:

 [self addSubview:[UIView viewWithNibName:@"CustomView" owner:self]]; 

Tenga en count también que el código anterior se puede refactorizar aún más, ya que la lógica es exactamente la misma en initWithFrame: y initWithCoder: ¡Espero que ayude!

Estoy asumiendo que la estructura de los XIB es algo como esto

 CustomView.xib CustomView UITextField -> linked to IBOutlet textField other views CustomViewController.xib CustomView 

Si esto es correcto, entonces se creará su CustomView, pero como no se lee desde CustomView.xib, no tiene asignados ningún IBOutlets.

Sin embargo, si su CustomViewController.xib se parece a seguir

 CustomViewController.xib CustomView UITextField -> linked to IBOutlet textField of CustomView 

entonces esto debería funcionar. La instancia IBOutlet de CustomView debe ser configurada por CustomViewController.xib.

Mejor que configurar cualquier IBOutlets en el CustomViewController.xib sería implementar awakeAfterUsingCoder: en su CustomView y crear un object de reemploop cargando su CustomView.xib allí. De esta forma, su CustomView permanece verdaderamente personalizado y no tiene que editar otros XIB para cambiar la estructura, agregar / eliminar IBOutlets, etc.

Como en la respuesta del Dr. Acula, esto probablemente se deba a que la punta de la vista personalizada se carga perezosa cuando se carga desde otra punta (carga de punta anidada), por lo que tenemos que instanciarla manualmente. En el código rápido, se verá así:

  override func awakeFromNib() { super.awakeFromNib() self.customview = UINib(nibName: "CustomViewNib", bundle: nil).instantiateWithOwner(self, options:nil)[0] as! UIView self.customview?.frame = self.viewContainer.bounds self.viewContainer.bounds.addSubview(self.customview!) }