2010-04-27 15 views
8

que han estado tratando de establecer un color de fondo UIImageView (véase más adelante) en awakeFromNibAccediendo a la vista en awakeFromNib?

[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]]; 

Cuando no funcionó, me di cuenta de que su probablemente porque la vista no se ha cargado todavía y que debería mover el cambio de color para verDidLoad.

¿Puedo verificar que tengo este derecho?

Gary

EDIT_002:

Me acaban de comenzar un nuevo proyecto para comprobar esto desde un comienzo limpio. Configuro la vista de la misma manera que siempre lo hago. El resultado es que los controles están configurados en (null) en awakeFromNib. Aquí es lo que tengo:

CÓDIGO:

@interface iPhone_TEST_AwakeFromNibViewController : UIViewController { 
    UILabel *myLabel; 
    UIImageView *myView; 
} 
@property(nonatomic, retain)IBOutlet UILabel *myLabel; 
@property(nonatomic, retain)IBOutlet UIImageView *myView; 
@end 

.

@synthesize myLabel; 
@synthesize myView; 

-(void)awakeFromNib { 
    NSLog(@"awakeFromNib ..."); 
    NSLog(@"myLabel: %@", [myLabel class]); 
    NSLog(@"myView : %@", [myView class]); 
    //[myLabel setText:@"AWAKE"]; 
    [super awakeFromNib]; 

} 

-(void)viewDidLoad { 
    NSLog(@"viewDidLoad ..."); 
    NSLog(@"myLabel: %@", [myLabel class]); 
    NSLog(@"myView : %@", [myView class]); 
    //[myLabel setText:@"VIEW"]; 
    [super viewDidLoad]; 
} 

SALIDA:

awakeFromNib ... 
myLabel: (null) 
myView : (null) 
viewDidLoad ... 
myLabel: UILabel 
myLabel: UIImageView 

Me interesaría saber si esto debería funcionar, a partir de los documentos que parece que debería, pero dada la forma en que suelo preparar las cosas que no puedo bastante entiende por qué no lo hace en este caso.

Respuesta

27

Una respuesta más :-) Parece que está obteniendo este comportamiento porque el controlador carga las vistas perezosamente. La vista no se carga inmediatamente, se carga la primera vez que alguien llama al accesorio view. Por lo tanto, en el momento en que recibe awakeFromNib el proceso de carga de NIB está hecho, pero no para los objetos dentro de sus vistas. Ver este código:

@property(retain) IBOutlet UILabel *foo; 
@synthesize foo; 

- (void) awakeFromNib 
{ 
    NSLog(@"#1: %i", !!foo); 
    [super awakeFromNib]; 
    NSLog(@"#2: %i", !!foo); 
} 

- (void) viewDidLoad 
{ 
    NSLog(@"#3: %i", !!foo); 
} 

Esto registra:

#1: 0 
#2: 0 
#3: 1 

Pero si se fuerza a cargar la vista:

- (void) awakeFromNib 
{ 
    [super awakeFromNib]; 
    [self view]; // forces view load 
    NSLog(@"#1: %i", !!foo); 
} 

Los cambios de registro en esto:

#3: 1 
#1: 1 
+0

Gracias Zoul, eso es muy interesante. Creo que es mejor utilizar viewDidLoad como forzar la vista para cargar llamadas primero de todos modos.También leí que usar awakeFromNib podría no ser una buena idea en el iPhone, pero parece que hay una opinión mixta sobre eso. Gracias de nuevo ... – fuzzygoat

+0

Si no tiene acceso a la vista, realice un Selector de rendimiento: withObject: demora la llamada desde awakeFromNib. Un truco, pero efectivo. – phatmann

+0

Acabo de tropezar con esta pregunta y respuesta por primera vez, ¡me hubiera ahorrado un montón de problemas si la hubiera encontrado antes! El problema persiste en 2013, y creo que el comportamiento contradice la documentación; consulte aquí: http://stackoverflow.com/questions/17400547/awakefromnib-outlets-and-storyboards-is-the-documentation-wrong –

-1

¿Estás seguro de que los objetos no son nil? NSAssert o NSParameterAssert son tus amigos:

-(void) awakeFromNib { 
    NSParameterAssert(imageView); 
    NSParameterAssert(testLabel); 
    NSLog(@"awakeFromNib ..."); 
    [imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]]; 
    [testLabel setText:@"Pants ..."]; 
    [super awakeFromNib]; 
} 

Si los objetos son realmente inicializan, tratar de registrar su dirección y asegúrese de que los casos que aparecen en viewDidLoad son los mismos que los de awakeFromNib:

- (void) awakeFromNib { 
    NSLog(@"test label #1: %@", testLabel); 
} 

- (void) viewDidLoad { 
    NSLog(@"test label #2: %@", testLabel); 
} 

Si los números son los mismos, puede crear una categoría para establecer un punto de interrupción en setBackgroundColor y echar un vistazo en el seguimiento de la pila para ver qué está pasando:

Usted puede hacer el mismo truco utilizando una subclase personalizada:

@interface PeekingView : UIImageView {} 
@end 

@implementation PeekingView 
- (void) setBackgroundColor: (UIColor*) whatever { 
    NSLog(@"Set a breakpoint here."); 
    [super setBackgroundColor:whatever]; 
} 
@end 

Ahora que puede establecer su UIViewObject a ser de clase PeekingView en el Interface Builder y sabrá cuando alguien trata de establecer el fondo. Esto debería detectar el caso en el que alguien sobrescribe los cambios de fondo después de inicializar la vista en awakeFromNib.

Pero supongo que el problema será mucho más simple, es decir. imageView es probablemente nil.

+0

Hola Zoul, muy apreciada, que pasará a través de sus sugerencias a primera hora de la mañana y dejar ya sabes cómo me llevo Probablemente tengas razón acerca de que es algo simple, déjame verlo mejor. – fuzzygoat

+0

Hola Zoul, los controles eran de hecho nulos, (Ver Edit_002 arriba) – fuzzygoat

1

Creo que su llamada a super necesita ser la primera línea en el método awakeFromNib, de lo contrario los elementos no se configurarán todavía.

-(void)awakeFromNib { 
    [super awakeFromNib]; 
    [imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]]; 
    [testLabel setText:@"Pants ..."]; 
} 
+2

Esta es una buena suposición y 'súper' debería llamarse primero, pero no ayuda en este caso. – zoul

0

Lo sé, esta publicación es un poco más antigua, pero recientemente tuve un problema similar y me gustaría compartir su solución con usted.

Al haber subplasmado NSTextView, quería mostrar los colores de las filas en órdenes alternas. Para ser capaz de alterar los colores del exterior, añadí dos instancias vars a mi subclase, XNSStripedTableView:

@interface XNSStripedTableView : NSTableView { 

    NSColor *pColor; // primary color 
    NSColor *sColor; // secondary color 
} 

@property (nonatomic, assign) NSColor *pColor; 
@property (nonatomic, assign) NSColor *sColor; 

@end 

sobrescritura highlightSelectionInClipRect: ¿el truco para establecer el color correcto para la respectiva clipRect.

- (void)highlightSelectionInClipRect:(NSRect)clipRect 

{

float rowHeight = [self rowHeight] + [self intercellSpacing].height; 
NSRect visibleRect = [self visibleRect]; 
NSRect highlightRect; 

highlightRect.origin = NSMakePoint(NSMinX(visibleRect), (int)(NSMinY(clipRect)/rowHeight)*rowHeight); 
highlightRect.size = NSMakeSize(NSWidth(visibleRect), rowHeight - [self intercellSpacing].height); 

while (NSMinY(highlightRect) < NSMaxY(clipRect)) { 

    NSRect clippedHighlightRect = NSIntersectionRect(highlightRect, clipRect); 
    int row = (int) ((NSMinY(highlightRect)+rowHeight/2.0)/rowHeight); 
    NSColor *rowColor = (0 == row % 2) ? sColor : pColor; 
    [rowColor set]; 
    NSRectFill(clippedHighlightRect); 
    highlightRect.origin.y += rowHeight; 
} 

[super highlightSelectionInClipRect: clipRect]; 

}

El único problema ahora es, dónde establecer los valores iniciales para pcolor y sColor? Intenté despertarFromNib :, pero esto causaría que el depurador apareciera con un error. Así que profundicé en el problema con NSLog: y encontré una solución fácil pero viable: establecer los valores iniciales en viewWillDraw:. Como los objetos no se crearon llamando al método la primera vez, tuve que verificar nil.

- (void)viewWillDraw { 

if (pColor == nil) 
    pColor = [[NSColor colorWithSRGBRed:0.33 green:0.33 blue:0 alpha:1] retain]; 

if (sColor == nil) 
    sColor = [[NSColor colorWithSRGBRed:0.66 green:0.66 blue:0 alpha:1] retain]; 

}

Creo que esta solución es bastante agradable :-) aunque se podría volver a seleccionar los nombres de pcolor y sColor podría ser ajustado para ser más "legible".

-1

En caso de que esté utilizando una subclase UIView en lugar de una subclase UIViewController, puede anular loadView método:

- (void)loadView 
{ 
    [super loadView]; 
    //IBOutlets are not nil here. 
}