2013-02-28 11 views
23

Ho avuto l'impressione che viewDidLoad venga chiamato DOPO che preparaForSegue finisce. Questo è anche il modo in cui Hegarty insegna alla sua classe di Stanford (fino a febbraio 2013).viewDidLoad chiamato prima di prepareForSegue termina

Tuttavia, per la prima volta oggi, ho notato che viewDidLoad è stato chiamato PRIMA che prepareForSegue era finito. Pertanto, le proprietà che stavo impostando in prepareForSegue non erano disponibili per destinationViewController all'interno del metodo viewDidLoad destinazioni.

Questo sembra contrario al comportamento previsto.

UPDATE

ho appena capito cosa stava succedendo. Nel mio destinationViewController ho avuto un setter personalizzato che ricaricare il tableView ogni volta che il "modello" è stato aggiornato:

DestinationViewController  
- (void)setManagedObjectsArray:(NSArray *)managedObjectsArray 
    { 
     _managedObjectsArray = [managedObjectsArray copy]; 
     [self.tableView reloadData]; 
    } 

Si scopre, dal momento che la destinationViewController è una sottoclasse di UITableViewController ... chiamare 'self.tableView' forza la vista a caricare. Secondo la documentazione di Apple, chiamare la proprietà view di un controller di visualizzazione può forzare il caricamento della vista. La vista di un UITableViewController è il tableView.

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html

Pertanto, nel prepareForSegue la seguente riga stava forzando la vista del destinationViewController a carico:

vc.managedObjectsArray = <custom method that returns an array>; 

per risolvere il problema, ho cambiato il setter personalizzato del modello del destinationViewController a:

- (void)setManagedObjectsArray:(NSArray *)managedObjectsArray 
    { 
     _managedObjectsArray = [managedObjectsArray copy]; 
     if ([self isViewLoaded]) { 
      [self.tableView reloadData]; 
     } 
    } 

Questo ricaricherà solo il TableView se il TableView è sullo schermo. Quindi non forzare la vista a caricare durante prepareForSegue.

Se qualcuno si oppone a questo processo, si prega di condividere i vostri pensieri. Altrimenti, spero che ciò impedisca una lunga notte insonne per qualcuno.

+1

Come sai che è stato chiamato viewDidLoad? Puoi condividere qualche codice? – Spectravideo328

+2

Sospetto che 'prepareForSegue' sia in effetti la funzione che (direttamente o indirettamente) chiama' viewDidLoad'. –

risposta

2

Grazie per la condivisione, mi ha aiutato a capire il mio problema.

Nel mio caso, il destinationViewController è un UITabBarController e la modifica è viewControllers Array ha attivato l'viewDidLoad:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    UITabBarController *tabBarController = segue.destinationViewController; 
    tabBarController.viewControllers = ... 
    tabBarController.something = something; 
} 

nel viewDidLoad avevo bisogno di qualcosa attributo da impostare, quindi ho dovuto spostarlo verso l'alto :

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    UITabBarController *tabBarController = segue.destinationViewController; 
    tabBarController.something = something; 
    tabBarController.viewControllers = ... 
} 
20

Avevo incontrato confusioni simili in passato. Le regole generali che ho imparato sono:

  1. prepareForSegue viene chiamato prima destinazione del VC viewDidLoad
  2. viewDidLoad viene chiamato solo dopo che tutti i punti vendita vengono caricati
  3. Non tentare di fare riferimento a qualsiasi destinazione punti di VC in fonte VC prepareForSegue.

Un'altra lezione appresa per preparareForSegue è evitare l'elaborazione ridondante. Ad esempio, se si segue già una cella TableView in un VC tramite storyboard, è possibile imbattersi in condizioni di competizione simili se si tenta di elaborare BOTH tableView: didSelectRowAtIndexPath e prepareForSegue. Si può evitare tale utilizzando il seguito manuale o rinunciare a qualsiasi elaborazione su didSelectRowAtIndexPath.

+0

Infatti, se si accede alle prese in 'initWithCoder:', richiama implicitamente il metodo 'viewDidLoad' prima di chiamare' prepareForSegue: '. grazie @ Hampde123 per il tuo commento che mi aiuta sulla mia strada – cdescours

1

la soluzione più semplice è quello di mettere

[self.tableView reloadData]; 

in viewWillAppear:

1

Ho pensato di aggiungere un po 'spiegazione su quanto accaduto qui:

prepareForSegue viene chiamato prima che venga visualizzata la vista

viewDidload viene chiamato la prima volta che si accede alla vista.

Ciò che probabilmente è accaduto è che si è effettuato l'accesso allo view in prepareForSegue attivando il caricamento della vista manualmente.

Di solito il flusso è:

  1. preformSegue
  2. prepareForSegue
  3. ViewController viene aggiunto alla gerarchia
  4. viewDidLoad.

Ma quello che probabilmente è accaduto nel tuo caso è:

  1. preformSegue
  2. prepareForSegue
  3. | - In prepareForSegue si accede al view
  4. | - view viene caricato automaticamente =>viewDidLoad è invocato
  5. Ritorno da performSegue
  6. ViewController si aggiunge alla gerarchia, non viewDidLoad (già chiamato)

Quindi sì di solito la proprietà view non si accede prima che si aggiunge alla gerarchia della ViewController, ma se lo è, viewDidLoad può essere attivato in precedenza.