2008-10-28 2 views
7

Mi stavo un po 'graffiando la testa una settimana fa, e ora con un po' di esperienza in più di cacao sotto la cintura mi sento come se avessi una vaga idea di cosa potrebbe succedere.ParentViewController è sempre un controller di navigazione?

Sto facendo un'applicazione guidata da un UINavigationController. In AppDelegate, creo un'istanza di questa classe, utilizzando "pagina 1" come Root View Controller.

UINavigationController *aNavigationController = [[UINavigationController alloc] 
    initWithRootViewController:page1ViewController]; 

Ora ecco dove sto avendo il problema. Dalla "pagina 1" mi piacerebbe utilizzare un controller modale di visualizzazione che scorre sull'interfaccia e quindi scompare una volta che l'utente ha apportato una modifica. Lo faccio utilizzando il codice come questo, all'interno di Page1ViewController:

[self presentModalViewController:myModalViewController animated:YES]; 

Quando il modale View Controller è andato, io voglio un valore su "Page 1" per cambiare in base a ciò che l'utente è entrato nel View Controller modale. Così, ho scritto qualche codice come questo, che risiede nella View Controller modale:

[self.parentViewController dismissModalViewControllerAnimated:YES]; 
[self.parentViewController doSomethingPleaseWithSomeData:someData]; 

L'aggiornamento a pagina 1 non stava accadendo, e ci ho messo molto tempo per rendersi conto che il messaggio "doSomethingPleaseWithSomeData" era non inviato a Page1 ViewController, ma al Navigation Controller.

E 'tutto da aspettarsi quando si usano i controlli di navigazione? Ho forse configurato qualcosa di inappropriato? C'è un modo semplice per ottenere il controller di visualizzazione che voglio (in questo caso, Page1ViewController).

risposta

14

Si consiglia di utilizzare lo schema di delega per risolvere il problema. Creare una proprietà

@property (nonatomic, assign) id <MyModalViewDelegate> delegate; 

e un corrispondente protocollo

@protocol MyModalViewDelegate 
@optional 
    - (void)myModalViewControllerDidFinish:(MyModalViewController *)aModalViewController; 
@end 

Quando l'utente termina con la vista (per esempio rubinetti sul pulsante di salvataggio), inviare questo messaggio:

if ([self.delegate respondsToSelector:@selector(myModalViewControllerDidFinish:)]) 
    [self.delegate myModalViewControllerDidFinish:self]; 

Ora, impostare il delegato al controller della vista che dovrebbe gestire l'intera operazione e verrà avvisato al termine del controllo della vista. Nota che avrai bisogno del tuo controller di visualizzazione per chiudere il controller della visualizzazione modale. Ma, logicamente, questo ha senso, dal momento che è stato l'oggetto che ha presentato il controller di visualizzazione modale in primo luogo.

Ecco come Apple risolve questo problema, ad esempio, UIImagePickerController e UIPersonPickerController.

4

Ci sono un paio di modi in cui puoi gestirlo. Il più semplice è probabilmente solo per aggiungere un alloggio UIViewController in myModalViewController e impostarlo per page1Controller prima di presentarlo:

myModalViewController.logicalParent = self; //page1Controller 
[self presentModalViewController:myModalViewController animated:YES]; 

Basta fare in modo di aggiungere l'istanza @property variabile appropriata, e @synthesize per logicalParent a myModalViewController, poi Avrai un modo per comunicare i dati al ViewController che ha attivato la finestra di dialogo modale. Questo è anche per passare i dati avanti e indietro tra diversi livelli di navigazione prima di spingerli e farli saltare in pila.

L'unica cosa importante di cui preoccuparsi quando si esegue questa operazione è che è facile ottenere i loop di conservazione se non si presta attenzione. A seconda del modo in cui si struttura ciò, potrebbe essere necessario utilizzare le proprietà di assegnazione.

+0

Compie esattamente ciò che voglio, grazie! Sono nuovo di Cocoa, ma non di MVC. Il fatto è che, essendo uno sviluppatore web Java, quasi sempre dimentico che i controller in "C" possono interagire tra loro! – bpapa

+0

Una buona risposta, ma perché è questo il caso? Chiaramente * non * quel caso che il controllore parentView della vista modale è il controller di navigazione in qualsiasi senso logico (page1Controller è il controller che richiede la visualizzazione modale), quindi perché Cocoa Touch lo ha impostato in questo modo? –

1

Mi sono imbattuto in questo stesso problema. Sembra assolutamente che se metti un UIViewController incorporato in un NavigationController, poi quando, da quel UIViewController, presenti un altro UIViewController modalmente, il presente pensa che il presentatore sia il NavigationController. In altre parole, parentViewController non è corretto.

Scommetto che questo è un bug: o quello, o la documentazione sembra incompleta. Mi informerò.

1

Appena incontrato lo stesso problema. Credo che questo sia un bug. Il mio scenario è il seguente: Una gerarchia di navigazione con i controller di visualizzazione A, B e C in questo ordine. Su C c'è un pulsante che aprirebbe un controller di visualizzazione modale chiamato D. Una volta che D viene presentato, il controller di navigazione rilascia C dalla sua gerarchia, il che è un comportamento terribile. Una volta che D viene rimosso, il controller di navigazione crea un nuovo un nuovo controller di visualizzazione di tipo C e lo inserisce nella sua gerarchia per ripristinare quello originale. Terribile. La mia soluzione è di hacking gerarchia di navigazione in questo modo (una pessima soluzione, ma funziona bene con una matrice 2 dimensione si potrebbe implementare modali accatastamento.):

- (void)presentModalViewController:(UIViewController *)c { 
    [self.navigationHierarchy removeAllObjects]; 
    [self.navigationHierarchy addObjectsFromArray:[navigation viewControllers]]; 
    [navigation setViewControllers:[NSArray array] animated:YES]; 
    [navigation presentModalViewController:c animated:YES]; 
} 

- (void)dismissModalViewController { 
    [navigation dismissModalViewControllerAnimated:YES]; 
    [navigation setViewControllers:[NSArray arrayWithArray:self.navigationHierarchy] animated:YES]; 
} 

Questi due metodi sono definiti in cui mantengo il hiererchy navigazione principale: il delegato dell'app. navigation and navigationhierarchy sono definiti in questo modo:

NSMutableArray *navigationHierarchy; 
UINavigationController *navigation;