ARC parece estar liberando la vista de mi NSViewController

Estoy tratando de resolver un problema más grande y estoy indicando el hecho de que ARC aparentemente está liberando la vista a mi NSViewController demasiado pronto. Creo :) Así que creé una aplicación simple para reconstruir la situación.

Tengo una aplicación ARC Cocoa simple. En la Ventana de la MainMenu.xib conecto un Custom View a una @property (strong) IBOutlet NSView *theView; que se declara en el AppDelegate.h

En la pestaña AppDelegate.m Sintetizo la propiedad y luego llamo a lo siguiente:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    TestViewController *tvc =  [[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil];
    [_theView addSubview:[tvc view]];
}  

Los programas TestViewControllerse muestra en el Custom View - no hay problema. Contiene un NSButton. Está conectado a un método llamado -(IBAction)btnPressed:(id)sender y un NSTextView que también está conectado como un IBOutlet.

En la pestaña TestViewController.h Declaro:

@property (nonatomic, strong) IBOutlet NSTextField *textField;
@property (nonatomic, strong) NSString *theString;

-(IBAction)btnPressed:(id)sender;

En la pestaña TestViewController.m Entonces lo hago

@synthesize theString = _theString;
@synthesize textField = _textField;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialization code here.
        _theString = @"Hello World";
    }

    return self;
}

-(IBAction)btnPressed:(id)sender
{
    [_textField setStringValue:_theString];
}

Cuando ejecuto la aplicación y presiono el botón, se bloquea. Si reviso si hay zombis, recibo lo siguiente:

#   Address Category    Event Type  RefCt   Timestamp   Size    Responsible Library Responsible Caller
0   0x7f97a3047560  TestViewController  Malloc  1   00:00.652.631   128 TestARC -[AppDelegate applicationDidFinishLaunching:]
1   0x7f97a3047560  TestViewController  Retain  2   00:00.653.088   0   TestARC -[TestViewController initWithNibName:bundle:]
2   0x7f97a3047560  TestViewController  Release 1   00:00.653.089   0   TestARC -[TestViewController initWithNibName:bundle:]
3   0x7f97a3047560  TestViewController  Retain  2   00:00.653.912   0   AppKit  -[NSNib instantiateNibWithOwner:topLevelObjects:]
4   0x7f97a3047560  TestViewController  Release 1   00:00.658.831   0   AppKit  -[NSNib instantiateNibWithOwner:topLevelObjects:]
5   0x7f97a3047560  TestViewController  Release 0   00:00.662.377   0   Foundation  -[NSNotificationCenter postNotificationName:object:userInfo:]
6   0x7f97a3047560  TestViewController  Zombie  -1  00:01.951.377   0   AppKit  -[NSApplication sendAction:to:from:]

¿Qué estoy haciendo mal? Gracias

preguntado el 28 de julio de 12 a las 12:07

2 Respuestas

Agregue una propiedad para contener el controlador de vista. Su controlador actualmente no tiene nada para mantenerlo vivo más allá del final del método que lo asigna.

Añadir:

@property (strong) TestViewController *tvc;

Modificar:

self.tvc =  [[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil];

(Tengo curiosidad... ¿cuál cree que es el punto de crear un controlador de vista si todo lo que quiere es la vista que contiene?)


Con respecto al enfoque general, parece que este es un comportamiento más adecuado que debería implementarse utilizando un controlador de vista de contenedor. Ese mecanismo permite que varios controladores de vista compartan la pantalla de forma organizada.

Respondido 28 Jul 12, 15:07

Estoy usando ViewControllers para cargar diferentes vistas (y sus respectivos métodos) en la vista personalizada que tengo en la ventana principal. Quería usar la vista personalizada como un "marco" para contenido intercambiable. Cambiando AppDelegate.h a @property (strong) IBOutlet TestViewController *theView; me obliga a quitarme el addSubview, ¿derecho? Pero eso no carga la vista de TestViewController en la vista personalizada... - Joseph

No, deja el addSubview si esa es la forma en que desea que funcione el diseño. Como dije, el subviews array se encargará de retenerlo. Solo el ciclo de vida del controlador fue un problema en su codificación original. (Sin embargo, la forma más compatible de obtener lo que creo que desea es mediante la creación de un controlador de vista de contenedor. Con esa estructura, existen métodos definidos para mantener una relación de controlador principal/secundario). - molinos phillip

si dejo la línea addSubview como está. Entonces me sale un error No visible @interface for 'TestViewController' declares the selector 'addSubview'. - Joseph

Lo siento... Hice una suposición incorrecta sobre cómo estabas usando la propiedad que has definido. En lugar de cambiar lo que tenía como propiedad, agregue una nueva para el controlador y asígnela cuando la cree. Actualizaré mi respuesta. - molinos phillip

Tengo otra pregunta a mi enfoque general: en mi aplicación tengo dos "secciones". Cada sección está separada entre sí, sin embargo, las molestias deben mostrarse una al lado de la otra. Es por eso que coloqué dos vistas personalizadas en la ventana principal y las conecté a las vistas de los dos ViewControllers. Quería separar lógica y "físicamente" el código. ¿Es esta la forma "incorrecta" de implementar lo que estaba tratando de hacer? - Joseph

Debe agregar un ivar o una propiedad para contener TextViewController. Actualmente, la única referencia a él desaparece al final de applicationDidFinishLaunching: lo que hace que se desasigne.

Eso es malo, porque su botón necesita que el controlador esté cerca para manejar la presión del botón. La vista no se aferra a su controlador, ya que eso provocaría un ciclo de retención. Por lo tanto, usted es responsable de mantener el controlador cerca si no desea que su botón se comunique con un objeto desasignado.

Respondido 28 Jul 12, 15:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.