2011-03-24 10 views
7

Ok, aquí hay otra pregunta.Cargando UIView desde un archivo de punta sin conjeturas

Estoy creando una UIView llamada ProgressView que es una vista semitransparente con un indicador de actividad y una barra de progreso.

Quiero ser capaz de utilizar esta vista en diferentes controladores de vista en mi aplicación, cuando sea necesario.

sé de 3 maneras diferentes de hacer esto (pero sólo estoy interesado en uno):

1) Crear toda la vista mediante programación, instanciar y configurar según sea necesario. No me preocupa que lo tenga.

2) Cree el UIView en el constructor de interfaz, agregue los objetos necesarios y cárguelo usando un método como el siguiente. El problema con esto es que básicamente estamos adivinando que la vista es objectAtIndex: 0 porque en ninguna parte de la documentación encontré una referencia al orden de los elementos devueltos por la función [[NSBundle mainBundle] loadNibName:.

NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"yournib" 
               owner:self 
               options:nil]; 
UIView *myView = [nibContents objectAtIndex:0]; 
myView.frame = CGRectMake(0,0,300,400); //or whatever coordinates you need 
[scrollview addSubview:myView]; 

3) Subclase UIViewController y permite administrar la vista como de costumbre. En este caso, yo nunca sería realmente empujando el controlador de vista en la pila, sino sólo su vista principal:

ProgressViewController *vc = [[ProgressViewController alloc] initWithNibName:@"ProgressView" bundle:nil]; 
[vc.view setCenter:CGPointMake(self.view.center.x, self.view.center.y)]; 
[self.view addSubview:vc.view]; 
[vc release]; 

Por lo que yo puedo decir, # 3 es la forma correcta de hacer esto (aparte de mediante programación) pero no estoy del todo seguro de si es seguro soltar el controlador de vista de ProgressView, mientras que la vista de otro controlador conserva su vista principal (¿la sensación interna dice que va a tener fugas?)?

¿Qué debo hacer en términos de gestión de memoria en este caso, dónde y cuándo debería liberar el controlador de vista de ProgressView?

Gracias de antemano por su opinión.

Saludos,

Rog

Respuesta

10

Creo que su solución n. ° 3 agrega complejidad innecesaria al presentar una instancia de UIViewController como un contenedor para su ProgressView para que pueda configurar enlaces de nib. Si bien creo que es agradable poder trabajar con una propiedad enlazada de IBOutlet en lugar de iterar a través del contenido de la punta, puede hacerlo sin introducir un UIViewController cuyo comportamiento no necesita ni desea. Esto debería evitar su confusión sobre cómo y cuándo liberar el controlador de vista y qué efectos secundarios podría tener en la cadena de respuesta u otros comportamientos de la vista cargada.

En su lugar, reconsidere el uso de NSBundle y aproveche el poder de ese argumento owner.

@interface ProgressViewContainer : NSObject { 

} 

@property (nonatomic, retain) IBOutlet ProgressView *progressView; 

@end 

@implementation ProgressViewContainer 

@synthesize progressView = progressView; 

- (void) dealloc { 
    [progressView release]; 
    [super dealloc]; 
} 

@end 

@interface ProgressView : UIView { 

} 

+ (ProgressView *) newProgressView; 

@end 

@implementation ProgressView 

+ (ProgressView *) newProgressView { 
    ProgressViewContainer *container = [[ProgressViewContainer alloc] init]; 
    [[NSBundle mainBundle] loadNibNamed:@"ProgressView" owner:container options:nil]; 

    ProgressView *progressView = [container.progressView retain]; 
    [container release]; 
    return progressView; 
} 

@end 

Crear una punta llamada "ProgressView" que contiene una ProgressView y establecer que es la clase de propietario del archivo a ProgressViewContainer. Ahora puedes crear ProgressViews cargado desde tu plumín.

ProgressView *progressView = [ProgressView newProgressView]; 
[scrollView addSubview:progressView]; 
[progressView release]; 

Si tiene varias configuraciones de su punto de vista el progreso entonces tal vez usted querrá poner en práctica un método -initWithNibNamed: en ProgressView en lugar de +newProgressView para que pueda especificar qué semilla a utilizar para crear cada instancia ProgressView.

+0

Parece bastante bueno para mí, gracias! – Rog

+2

¿Puedo comentar que creo que aún recibirá el error si establece el propietario en sí mismo como se muestra en el código. Corrígeme si me equivoco, pero la única forma en que pude lograr esto fue haciendo que el propietario sea el objeto "contenedor". –

+0

Oye, esto funciona para mí, gracias. Diré que es un poco extraño, no exactamente intuitivo. Olvidé conectar el IBOutlet la primera vez, por ejemplo. Parece que Apple debería hacer que esta capacidad sea un poco más fácil de acceder. – Jeff

3

Yo voto por la opción 2 #. El valor de retorno de - [NSBundle loadNibNamed] es una matriz de objetos de nivel superior. Por lo tanto, siempre que solo tenga un objeto de nivel superior en su plumilla, entonces el índice 0 será correcto. Las otras vistas son subvistas y no objetos de nivel superior.

Otra opción, por supuesto, es crear una superclase para todos sus controladores de vista que incluya una salida llamada 'progressView' y luego conectar su vista a esa salida en el propietario del archivo en la punta. Sin embargo, parece exagerado por esto.

3

También prefiero la alternativa n. ° 2. Si el "0" que le está molestando, usted podría:

  • Crear una subclase de UIView llama ProgressView
  • Crear una punta-archivo llamado ProgressView.xib que describe su visión de progreso.
  • seleccionar la vista superior en su punta, y establecer su clase a la ProgressView en constructor de interfaces

luego hacer

NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"ProgressView" owner:self options:nil]; 
ProgressView *progressView = nil; 

for (UIView *view in nibContents) { 
    if ([view isKindOfClass:[ProgressView class]]) { 
     progressView = (ProgressView *) view; 
     break; 
    } 
} 

if (progressView != nil) { 
    //Use progressView here 
} 
3

que terminó la adición de una categoría a la UIView para esto:

#import "UIViewNibLoading.h" 

@implementation UIView (UIViewNibLoading) 

+ (id) loadNibNamed:(NSString *) nibName { 
    return [UIView loadNibNamed:nibName fromBundle:[NSBundle mainBundle] retainingObjectWithTag:1]; 
} 

+ (id) loadNibNamed:(NSString *) nibName fromBundle:(NSBundle *) bundle retainingObjectWithTag:(NSUInteger) tag { 
    NSArray * nib = [bundle loadNibNamed:nibName owner:nil options:nil]; 
    if(!nib) return nil; 
    UIView * target = nil; 
    for(UIView * view in nib) { 
     if(view.tag == tag) { 
      target = [view retain]; 
      break; 
     } 
    } 
    if(target && [target respondsToSelector:@selector(viewDidLoad)]) { 
     [target performSelector:@selector(viewDidLoad)]; 
    } 
    return [target autorelease]; 
} 

@end 

explicación aquí: http://gngrwzrd.com/blog-view-controller-less-view-loading-ios-mac.html

Cuestiones relacionadas