2011-05-02 6 views
17

¿Cómo cargo correctamente un objeto que es una subclase de NSView utilizando un Xib?cargando programáticamente el objeto desde la subclase de NSView desde la punta

quiero que se cargue dinámicamente no desde el principio, así que hice una MyView.Xib De MyDocument.m que hice:

MyView *myView = [[MyView alloc] initWithFrame:...]; 
[NSBundle loadNibNamed:@"MyView" owner:myView]; 
[someview addSubview:myView]; 
... 

y el fondo está muy bien (que llama drawRect: y se dibuja como se esperaba) pero no aparecerán todos los botones que puse en el xib. He comprobado, y están cargados PERO su supervista no es el mismo objeto que myView.

¿Por qué es esto? Creo que me falta algo en el Xib, pero no sé exactamente qué. En otras palabras: ¿cómo me aseguro de que la vista raíz en mi xib sea el mismo objeto que el propietario del archivo?

Me gustaría que hubiera algo similar a esto para el mac:

NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil]; //in iOS this will load the xib 
MyView* myView = [ nibViews objectAtIndex:1]; 
[someview addSubview:myView]; 
... 

Gracias de antemano.

EDITAR

Creo que me he dado cuenta el origen del problema ... (??)

En la clase MyView tengo varios IBOutlet que están conectados correctamente en IB es por eso que se carguen muy bien (puedo referirlos). Sin embargo, no hay IBOutlet para la vista superior. Entonces, cuando NSBundle carga el plumín, la vista superior se asigna a algún otro objeto. Pensé que esto sucedería si configuro mi vista superior en IB como perteneciente a la clase: MyView y pongo myView como propietario en [NSBundle loadNibNamed:@"MyView" owner:myView];, pero parece que no es el caso. ¿Qué estoy haciendo mal?

+0

Intenta moverlos al frente tal vez lo dibuje en la parte posterior y no se puede ver debido al fondo – Radu

+0

Acabo de intentar ...eso no está sucediendo; ( – nacho4d

+0

En su archivo de punta, ¿hay una vista de nivel superior cuya clase es 'MyView'? ¿Hay otros objetos de nivel superior en el archivo de punta? ¿Y cuál es la clase del propietario del archivo? –

Respuesta

28

Tenga en cuenta que un archivo semilla contiene:

  • Uno o más objetos de nivel superior. Por ejemplo, una instancia de MyView;
  • Marcador de posición del propietario de un archivo. Este es un objeto que existe antes de que se cargue el archivo nib. Dado que existe antes de que se cargue el archivo nib, no puede ser igual a la vista en el archivo nib.

Escenario 1: NSNib

Vamos a considerar que su archivo de punta tiene un solo objeto de nivel superior cuya clase es MyView, y la clase propietario del archivo es MyAppDelegate. En ese caso, teniendo en cuenta que el archivo se carga en punta de un método de instancia de MyAppDelegate:

NSNib *nib = [[[NSNib alloc] initWithNibNamed:@"MyView" bundle:nil] autorelease]; 
NSArray *topLevelObjects; 
if (! [nib instantiateWithOwner:self topLevelObjects:&topLevelObjects]) // error 

MyView *myView = nil; 
for (id topLevelObject in topLevelObjects) { 
    if ([topLevelObject isKindOfClass:[MyView class]) { 
     myView = topLevelObject; 
     break; 
    } 
} 

// At this point myView is either nil or points to an instance 
// of MyView that is owned by this code 

Parece que el primer argumento de -[NSNib instantiateNibWithOwner:topLevelObjects:] puede ser nil por lo que no tendría que especificar un propietario ya que parece que usted no está interesado en tener uno:

if (! [nib instantiateWithOwner:nil topLevelObjects:&topLevelObjects]) // error 

Aunque esto funciona, no confiaría en él ya que no está documentado.

Tenga en cuenta que usted es el propietario de los objetos de nivel superior, por lo tanto, usted es responsable de liberarlos cuando ya no sean necesarios.

Escenario 2: NSViewController

Cocoa proporciona NSViewController para administrar puntos de vista; usualmente, vistas cargadas desde un archivo de punta. Debe crear una subclase de NSViewController que contenga los puntos de venta necesarios. Al editar el archivo de plumillas, configure la toma view y las otras salidas que haya definido. También debe establecer el propietario del archivo nib para que su clase sea esta subclase de NSViewController. Entonces:

MyViewController *myViewController = [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil]; 

NSViewController carga automáticamente el archivo semilla y establece las salidas correspondientes cuando lo envía -view. De forma alternativa, puede forzarlo a que cargue el archivo nib enviándolo -loadView.

+0

Mi plumilla tiene solo un objeto de nivel superior cuya clase es" MyView "pero el el propietario del archivo también es "MyView", ¿es posible? – nacho4d

+0

Es posible si tiene otra instancia de 'MyView' que se haya creado antes de que se cargue el archivo nib. Tenga en cuenta que esto implica que esta otra instancia ha sido creada programáticamente o cargado desde otro archivo nib, diferente de MyView.nib. –

+0

Tengo una instancia MyView * myView que se ha creado usando [[MyView alloc] initWithFrame:]; Estoy usando eso en el propietario de [NSBundle loadNib: @ "MyView": myView]; I aún no entiendo por qué esto no está funcionando; ( – nacho4d

5

puede hacer referencia a esta categoría

https://github.com/peterpaulis/NSView-NibLoading-/tree/master

+ (NSView *)loadWithNibNamed:(NSString *)nibNamed owner:(id)owner class:(Class)loadClass { 

    NSNib * nib = [[NSNib alloc] initWithNibNamed:nibNamed bundle:nil]; 

    NSArray * objects; 
    if (![nib instantiateWithOwner:owner topLevelObjects:&objects]) { 
     NSLog(@"Couldn't load nib named %@", nibNamed); 
     return nil; 
    } 

    for (id object in objects) { 
     if ([object isKindOfClass:loadClass]) { 
      return object; 
     } 
    } 
    return nil; 
} 
1

he encontrado la respuesta por @Bavarious muy útil, pero todavía se necesita un poco de squirrelling de mi parte para hacer que funcione para mi caso de uso - cargue una de las varias definiciones de vista de xib en una vista existente de "contenedor". Aquí está mi flujo de trabajo:

1) En .xib, cree la vista en IB como se esperaba.

2) No agregue un objeto para viewController de la nueva vista, sino más bien

3) Establecer de Archivo de la .xib propietario de nuevo de vista viewController

4) Conectar las salidas & acciones a de archivo de propietario, y, específicamente, .view

5) Llamar a loadInspector (ver a continuación).

enum InspectorType { 
    case None, ItemEditor, HTMLEditor 

    var vc: NSViewController? { 
     switch self { 
     case .ItemEditor: 
      return ItemEditorViewController(nibName: "ItemEditor", bundle: nil) 
     case .HTMLEditor: 
      return HTMLEditorViewController(nibName: "HTMLEditor", bundle: nil) 
     case .None: 
      return nil 
     } 
    } 
} 

class InspectorContainerView: NSView { 

    func loadInspector(inspector: InspectorType) -> NSViewController? { 
     self.subviews = [] // Get rid of existing subviews. 
     if let vc = inspector.vc { 
      vc.loadView() 
      self.addSubview(vc.view) 
      return vc 
     } 
     Swift.print("VC NOT loaded from \(inspector)") 
     return nil 
    } 
} 
0
class CustomView: NSView { 

@IBOutlet weak var view: NSView! 
@IBOutlet weak var textField: NSTextField! 

required init(coder: NSCoder) { 
    super.init(coder: coder)! 

    let frameworkBundle = Bundle(for: classForCoder) 
    assert(frameworkBundle.loadNibNamed("CustomView", owner: self, topLevelObjects: nil)) 
    addSubview(view) 
} 

}

0

Aquí es una manera de escribir la subclase NSView por lo que la vista en sí viene completamente de una xib separada y tiene todo configurado correctamente. Se basa en el hecho de que init puede cambiar el valor de self.

Crea una nueva 'vista' xib usando Xcode. Establezca la clase del propietario del archivo en NSViewController y establezca su salida view en su vista de destino. Establezca la clase de la vista de destino en su subclase NSView. La disposición de su punto de vista, conectar las salidas etc.

Ahora, en la subclase NSView, poner en práctica los inicializadores designados:

- (id)initWithFrame:(NSRect)frameRect 
{ 
    NSViewController *viewController = [[NSViewController alloc] init]; 
    [[NSBundle mainBundle] loadNibNamed:@"TheNib" owner:viewController topLevelObjects:NULL]; 

    id viewFromXib = viewController.view; 
    viewFromXib.frame = frameRect; 
    self = viewFromXib; 
    return self; 
} 

y lo mismo con initWithCoder: de modo que también funciona si se utiliza la subclase NSView en una otra xib.

Cuestiones relacionadas