from ios uiview init iboutlet loadnibnamed

ios - load view from xib swift 4



iOS loadNibNamed confusión, ¿cuál es la mejor práctica? (3)

Aquí hay un método que utilizo:

  1. Cree una subclase para UIView , esto se llamará MyClass
  2. Crea un archivo xib de vista. Abra en el constructor de interfaces, haga clic en Propietario del archivo y en el Inspector de identidad, cambie la clase a la de su controlador de vista principal, por ejemplo, ParentViewController .
  3. Haga clic en la vista que ya está en la lista de objetos y cambie su clase en Identity Inspector a MyClass .
  4. Todas las salidas / acciones que declare en MyClass se conectarán haciendo clic y arrastrando desde Ver (no el propietario del archivo). Si desea conectarlos a las variables de ParentViewController , haga clic y arrastre desde el propietario del archivo.
  5. Ahora en su ParentViewController debe declarar una variable de instancia para MyClass .

ParentViewController.h agrega lo siguiente:

@class MyClass @interface ParentViewController : UIViewController { MyClass *myClass; } @property (strong, nonatomic) MyClass *myClass;

Sintetice esto en su implementación y agregue lo siguiente en su método viewDidLoad :

- (void)viewDidLoad { [super viewDidLoad]; [[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:self options:nil]; self.myClass.frame = CGRectMake(X,Y,W,H); //put your values in. [self.view addSubview:self.myClass]; }

Estoy familiarizado con la mayor parte del proceso de creación de un XIB para mi propia subclase UIView, pero no todo está funcionando correctamente para mí, se debe principalmente a la vinculación de los IBOutlets. Puedo hacer que funcionen en lo que parece una forma indirecta.

Mi configuración es la siguiente:

  • Tengo MyClass.h y MyClass.m. Tienen IBOutlets para un UIView (llamado vista) y un UILabel (llamado myLabel). Agregué la propiedad ''ver'' porque algunos ejemplos en línea parecían sugerir que necesitas esto, y en realidad resolvió un problema en el que tenía un fallo porque no podía encontrar la propiedad vista, supongo que ni siquiera en la clase padre UIView .
  • Tengo un archivo XIB llamado MyClass.xib, y su clase personalizada del propietario del archivo es MyClass, que se completó correctamente después de que existiera mi .h y .m para esa clase.

Mi método de inicio es donde estoy teniendo problemas.

Intenté usar el método ''loadNibNamed'' de NSBundle mainBundle y configuré al propietario como ''self'', con la esperanza de que estuviera creando una instancia de la vista y que hiciera coincidir sus puntos de venta con los de mi clase (lo sé cómo hacer esto y tengo cuidado con ello). Entonces pensé que me gustaría hacer que ''yo'' sea igual a la subvista en el índice 0 en esa punta, en lugar de hacerlo

self = [super init];

o algo por el estilo.

Siento que estoy haciendo las cosas mal aquí, pero los ejemplos en línea han tenido cosas similares en el método init, pero asignan esa subvista 0 a la propiedad de vista y la agregan como un niño, pero no es un total de dos instancias de MyClass? ¿Uno esencialmente no vinculado a IBOutlets, que contiene el MyClass secundario creado a través de loadNibNamed? O, en el mejor de los casos, ¿no es una instancia de MyClass con una UIView intermedia adicional que contiene todos los IBOutlets que originalmente quería como hijos directos de MyClass? Eso plantea una pequeña molestia cuando se trata de hacer cosas como instanceOfMyClass.frame.size.width, ya que devuelve 0, cuando la vista UIV secundaria introducida devuelve el tamaño de marco real que estaba buscando.

¿Lo que estoy haciendo mal es que estoy jugando con loadNibNamed dentro de un método init? ¿Debería estar haciendo algo más como esto?

MyClass *instance = [[MyClass alloc] init]; [[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:instance options:nil];

¿O así?

MyClass *instance = [[[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:nil options:nil] objectAtIndex:0];

Gracias de antemano por cualquier asistencia.


La segunda opción es la correcta. El código más defensivo que podrías hacer es así:

+ (id)loadNibNamed:(NSString *)nibName ofClass:(Class)objClass { if (nibName && objClass) { NSArray *objects = [[NSBundle mainBundle] loadNibNamed:nibName owner:nil options:nil]; for (id currentObject in objects ){ if ([currentObject isKindOfClass:objClass]) return currentObject; } } return nil; }

Y llamar así:

MyClass *myClassInstance = [Utility loadNibNamed:@"the_nib_name" ofClass:[MyClass class]]; // In my case, the code is in a Utility class, you should // put it wherever it fits best

Supongo que su MyClass es una subclase de UIView ? Si ese es el caso, entonces debes asegurarte de que la vista UIView de tu .xib sea en realidad de la clase MyClass. Eso se define en la tercera pestaña en la parte derecha del generador de interfaz, después de seleccionar la vista


Todo lo que necesita hacer es crear la subvista a través de loadNibNamed , establecer el marco y agregarla a la subvista. Por ejemplo, estoy agregando tres subvistas usando mi clase MyView , que es una subclase UIView cuya interfaz está definida en un NIB, MyView.xib :

Entonces, defino initWithFrame para mi subclase UIView :

- (id)initWithFrame:(CGRect)frame { NSLog(@"%s", __FUNCTION__); self = [super initWithFrame:frame]; if (self) { NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil]; [self addSubview:nibContents[0]]; } return self; }

Así, por ejemplo, en mi UIViewController , puedo cargar un par de estos objetos UIView subclasificados como:

for (NSInteger i = 0; i < 3; i++) { CGRect frame = CGRectMake(0.0, i * 100.0 + 75.0, 320.0, 100.0); MyView *myView = [[MyView alloc] initWithFrame:frame]; [self.view addSubview:myView]; // if you want, do something with it: // Here I''m initializing a text field and label myView.textField.text = [NSString stringWithFormat:@"MyView textfield #%d", i + 1]; myView.label.text = [NSString stringWithFormat:@"MyView label #%d", i + 1]; }

Originalmente aconsejé a los controladores de uso y mantendré esa respuesta a continuación como referencia histórica.

Respuesta original:

No veo ninguna referencia para ver los controladores aquí. Por lo general, tendrías una subclase de UIViewController , que luego instanciarías con

MyClassViewController *controller = [[MyClassViewController alloc] initWithNibName:@"MyClass" bundle:nil]; // then you can do stuff like // // [self presentViewController:controller animated:YES completion:nil];

El archivo NIB, MyClass.xib , podría especificar que la clase base para UIView , si lo desea, donde tenga todo el código relacionado con la vista (por ejemplo, suponiendo que MyClass fuera una subclase de UIView ).