2010-01-14 13 views
5

Sto aprendo una nuova domanda per il followup sul mio ultimo (superview and parentviewcontroller nil after adding a subview). Fondamentalmente ho capito che usare i sottoview è una buona idea, ma che non dovrei avere un ViewController che controlla una sottoview che risiede in un altro ViewController. Fondamentalmente mi piacerebbe fare il seguente ... Ho due ViewControllers che condividono una sottoview comune. Ho creato questa sottoview come pennino chiamato SearchDate.xib. Il proprietario del file è una classe corrispondente SearchDateView.m/h. Quella classe ha uno sbocco per l'unico elemento all'interno di UIView nel pennino che è un'etichetta. La classe SearchDateView ha anche una funzione per modificare il valore dell'etichetta in SearchDateView.xib. Mi piacerebbe che entrambi i miei ViewController caricassero questo pennino ma a quanto pare non ho idea di come caricare correttamente il pennino. Non importa quello che faccio nel migliore dei casi non viene visualizzato nulla e nel peggiore dei casi viene generata un'eccezione. I documenti Apple parlano di trascinamento in altre istanze di classi in IB direttamente nella tua vista principale, ma ciò sembra non funzionare. Ho una presa SearchDateView nel mio ViewController e ho provato a fare questo in mostra carico del controller:Come posso creare un pennino con una classe di visualizzazione associata che può essere utilizzata da più ViewController

searchDateView = [[[NSBundle mainBundle] loadNibNamed:@"SearchDateView" owner:self options:nil] objectAtIndex:0]; 
[[self view] addSubview:searchDateView]; 

Ma ottengo questa eccezione:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainViewController 0x431fac0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchDateLabel.' 

so che sto facendo qualcosa di totalmente sbagliato ma cosa è il modo giusto per avere un pennino, una classe di vista associata che aggiorna alcuni oggetti in quel pennino e riutilizzare quel pennino in diversi controller?

EDIT: Dato il commento forse questo non era abbastanza chiaro. Non voglio usare lo stesso file pennino per un'intera vista - piuttosto una sottoview. Quindi per esempio il controller A ha una mappa e anche un SearchDateView, e il controller B ha una vista tabella e un SearchDateView. Quindi mi chiedo come caricare una sottoview in più controller ...

risposta

2

Non ci dovrebbero essere problemi nell'usare lo stesso file NIB per più controller quando ognuno viene inizializzato usando initWithNibName: bundle :. Tuttavia, normalmente non si carica il proprio file di pennino dal controller.

Se si carica un file di pennino con loadNibNamed :::, si ottiene un NSArray con gli oggetti definiti al suo interno, quindi non è possibile utilizzarlo direttamente come vista. Un modo per ottenere una vista è cercare nell'array usando for() o qualcosa per trovare l'oggetto che si desidera, ma se si imposta owner: self allora dovrebbe connettersi alle prese collegate al proprietario del file in self come Owner di File sarà self . Ma in questo caso puoi scartare il valore restituito; non hai bisogno dell'array restituito. Questo potrebbe essere il tuo problema principale (sbattere contro l'uscita con l'array) se hai collegato quella presa.

È possibile utilizzare loadNibNamed per caricare un oggetto di visualizzazione specifico (presupponendo che lo si scelga dall'array restituito), quindi visualizzarlo in qualche modo, ma in genere è più semplice utilizzare initWithNibName sul controller (nel qual caso il proprietario del file verrà essere il controller).

Oh, ed è anche possibile impostare il file pennino per un controller in Interface Builder. Non dovrebbe esserci un problema con l'utilizzo dello stesso pennino per più controller poiché in pratica si direbbe a Interface Builder di configurare il file pennino per fare qualcosa come initWithNibNamed. Fare clic sull'oggetto controller e controllare la finestra dell'ispettore.

Aggiornamento

probabilmente sarei fare questo al fine di utilizzare solo una vista in più controller:

NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"FooView" 
               owner:self options:nil]; 
    for (id obj in nib) 
     if ([obj isKindOfClass:[FooView class]]) 
      myNewView = (FooView *)obj; 

(rubato dal capitolo 8: Celle 2 nel codice di esempio da Beginning Sviluppo iPhone 3.)

Si potrebbe fare questo con gli outlet in IB, nel qual caso si potrebbe tralasciare il ciclo for, ma probabilmente avrai bisogno di una superclasse per entrambi i controller che dichiarano la presa e qualcosa da dire a Interface Builder che il proprietario di File è un'istanza di quella superclasse in modo che sappia della presa. Probabilmente non ne vale la pena.

+0

Scusa forse non ero troppo chiaro. Non voglio usare lo stesso file pennino per un'intera vista - piuttosto una sottoview. Quindi per esempio il controller A ha una mappa e anche un SearchDateView, e il controller B ha una vista tabella e un SearchDateView. Quindi mi sto chiedendo come caricare una sottoview in più controller. – deadroxy

+0

Ho aggiornato la mia risposta per essere più specifico della vostra situazione. – Nimrod

+0

Sì, la superclasse sembra essere l'unica soluzione "reale" al mio problema. Probabilmente rifatterò in seguito, ma per ora ho trovato qualche soluzione - grazie! – deadroxy

0

Ho una presa di SearchDateView nel mio ViewController e ho provato a fare questo in mostra carico del controller:

searchDateView = [[[NSBundle mainBundle] loadNibNamed:@"SearchDateView" owner:self options:nil] objectAtIndex:0]; 
[[self view] addSubview:searchDateView]; 

ma ottengo questa eccezione:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainViewController 0x431fac0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchDateLabel.' 

In assenza di Cocoa Bindings (che è disponibile solo in Cocoa, non in Cocoa Touch), non penso che questi due siano correlati.

In Xcode, aggiungere un punto di interruzione simbolico su objc_exception_throw, quindi eseguire l'app nel debugger. Quando si rompe, guarda nello stack delle chiamate. Sarai in grado di scoprire da dove proviene veramente il problema.