2010-04-27 21 views
8

Mi hanno cercato di impostare un colore UIImageView di sfondo (vedi sotto) in awakeFromNibAccesso alla vista in awakeFromNib?

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

Quando non ha funzionato, mi sono reso conto che la sua probabilmente perché la vista non ha ancora caricato e mi dovrebbe spostare il cambiamento di colore per visualizzareDidLoad.

Posso solo verificare che ho ragione?

Gary

EDIT_002:

ho appena iniziato un nuovo progetto di controllare questo da un inizio pulito. Ho impostato la vista come sempre. I risultati sono che i controlli sono effettivamente impostati su (null) in awakeFromNib. Ecco quello che ho:

CODICE:

@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]; 
} 

USCITA:

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

Sarei interessato a sapere se questo dovrebbe funzionare, dalla documentazione sembra che dovrebbe, ma dato il modo in cui io di solito impostare le cose non riesco a capire perché non in questo caso.

risposta

27

Una risposta più :-) Sembra che stai ricevendo questo comportamento perché il controller carica la vista pigramente. La vista non viene caricata immediatamente, viene caricata la prima volta che qualcuno chiama l'accessor view. Pertanto nel momento in cui si riceve awakeFromNib il processo di caricamento NIB è terminato, ma non per gli oggetti all'interno delle viste. Vedere questo codice:

@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); 
} 

Questo registra:

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

Ma se si forza-caricare la visualizzazione:

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

I cambiamenti accedere a questo:

#3: 1 
#1: 1 
+0

Grazie Zoul, questo è molto interessante. Credo che sia meglio usare viewDidLoad per forzare la vista a caricare prima le chiamate.Ho anche letto che l'uso di awakeFromNib potrebbe non essere una buona idea su iPhone, ma sembra esserci un parere contrastante su questo. Grazie ancora ... – fuzzygoat

+0

Se non hai accesso alla vista, esegui performSelector: withObject: delay call da awakeFromNib. Un hack, ma efficace. – phatmann

+0

Sono appena incappato in questa domanda e ho risposto per la prima volta - mi avrebbe risparmiato un sacco di problemi se l'avessi trovato prima! Il problema esiste ancora nel 2013 e ritengo che il comportamento sia in contraddizione con la documentazione - vedi qui: http://stackoverflow.com/questions/17400547/awakefromnib-outlets-and-storyboards-is-the-documentation-wrong –

-1

Sei sicuro che gli oggetti non sono nil? NSAssert o NSParameterAssert sono i tuoi amici:

-(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]; 
} 

Se gli oggetti sono davvero inizializzati, tenta di accedere il loro indirizzo e assicurarsi che le istanze che compaiono nel viewDidLoad sono gli stessi di quelli in awakeFromNib:

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

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

Se i numeri sono uguali, è possibile creare una categoria per impostare un punto di interruzione su setBackgroundColor e sbirciare nello stack trace per vedere cosa sta succedendo:

@implementation UIImageView (Patch) 
- (void) setBackgroundColor: (UIColor*) whatever { 
    NSLog(@"Set a breakpoint here."); 
} 
@end 

Si può fare lo stesso trucco con una sottoclasse personalizzata:

@interface PeekingView : UIImageView {} 
@end 

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

Ora dovrai impostare l'UIViewObject essere di classe PeekingView in Interface Builder e saprete quando qualcuno tenta di impostare lo sfondo. Questo dovrebbe catturare il caso in cui qualcuno sovrascrive le modifiche allo sfondo dopo aver inizializzato la vista in awakeFromNib.

Ma presumo che il problema sarà molto più semplice, vale a dire. imageView è molto probabilmente nil.

+0

Hi Zoul, molto apprezzato, mi passerà attraverso i vostri suggerimenti prima cosa la mattina e lasciare sai come vado avanti Probabilmente hai ragione sul fatto che sia qualcosa di semplice, fammi avere un aspetto migliore. – fuzzygoat

+0

Ciao Zoul, i controlli erano davvero nulli, (vedi Modifica_002 sopra) – fuzzygoat

1

Credo che la tua chiamata a super debba essere la prima riga nel metodo awakeFromNib, altrimenti gli elementi non saranno ancora impostati.

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

Questa è una buona ipotesi e "super" dovrebbe essere effettivamente chiamato prima, ma in questo caso non aiuta. – zoul

0

Lo so, questo post è un po 'più vecchio, ma di recente l'ho avuto un problema simile e vorrei condividere la sua soluzione con voi.

Avendo sottoclasse NSTextView, ho voluto per visualizzare i colori delle righe in ordini alternati. Per essere in grado di alterare i colori dall'esterno, ho aggiunto due esempio vars al mio sottoclasse, XNSStripedTableView:

@interface XNSStripedTableView : NSTableView { 

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

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

@end 

sovrascrittura highlightSelectionInClipRect: fa il trucco per impostare il colore corretto per il rispettivo 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]; 

}

L'unico problema ora è, dove impostare i valori iniziali per pColor e Scolor? Ho provato awakeFromNib :, ma questo avrebbe causato un errore nel debugger. Così ho risolto il problema con NSLog: e ho trovato una soluzione semplice ma praticabile: impostare i valori iniziali in viewWillDraw:. Poiché gli oggetti non vengono creati chiamando il metodo la prima volta, ho dovuto verificare per 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]; 

}

Io credo che questa soluzione è molto bello :-) anche se si poteva selezionare nuovamente i nomi di pColor e Scolor potrebbe essere regolato per essere più "leggibile".

-1

Nel caso in cui si sta utilizzando una sottoclasse UIView invece di una sottoclasse UIViewController, è possibile ignorare loadView metodo:

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