dismissModalViewController E restituisce i dati


84

Ho due controller di visualizzazione, firstViewController e secondViewController . Sto usando questo codice per passare al mio secondViewController (sto anche passando una stringa ad esso):

secondViewController *second = [[secondViewController alloc] initWithNibName:nil bundle:nil];

second.myString = @"This text is passed from firstViewController!";

second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

[self presentModalViewController:second animated:YES];

[second release];

Quindi utilizzo questo codice in secondViewController per tornare al firstViewController:

[self dismissModalViewControllerAnimated:YES];

Tutto questo funziona bene. La mia domanda è: come passerei i dati al firstViewController? Vorrei passare una stringa diversa nel firstViewController dal secondViewController.

Risposte:


142

È necessario utilizzare i protocolli delegato ... Ecco come farlo:

Dichiara un protocollo nel file di intestazione del tuo secondViewController. Dovrebbe sembrare come questo:

#import <UIKit/UIKit.h>

@protocol SecondDelegate <NSObject>
-(void)secondViewControllerDismissed:(NSString *)stringForFirst
@end


@interface SecondViewController : UIViewController
{
    id myDelegate;  
}

@property (nonatomic, assign) id<SecondDelegate>    myDelegate;

Non dimenticare di sintetizzare il myDelegate nel file di implementazione (SecondViewController.m):

@synthesize myDelegate;

Nel file di intestazione di FirstViewController iscriviti al protocollo SecondDelegate in questo modo:

#import "SecondViewController.h"

@interface FirstViewController:UIViewController <SecondDelegate>

Ora, quando installi SecondViewController in FirstViewController, dovresti fare quanto segue:

// If you're using a view controller built with Interface Builder.
SecondViewController *second = [[SecondViewController alloc] initWithNibName:"SecondViewController" bundle:[NSBundle mainBundle]];
// If you're using a view controller built programmatically.
SecondViewController *second = [SecondViewController new]; // Convenience initializer that uses alloc] init]
second.myString = @"This text is passed from firstViewController!";
second.myDelegate = self;
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];

Infine, nel file di implementazione per il tuo primo controller di visualizzazione (FirstViewController.m) implementa il metodo SecondDelegate per secondViewControllerDismissed:

- (void)secondViewControllerDismissed:(NSString *)stringForFirst
{
    NSString *thisIsTheDesiredString = stringForFirst; //And there you have it.....
}

Ora, quando stai per chiudere il secondo controller di visualizzazione, vuoi richiamare il metodo implementato nel primo controller di visualizzazione. Questa parte è semplice. Tutto quello che fai è, nel tuo secondo controller di visualizzazione, aggiungere del codice prima del codice di eliminazione:

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!"];
}
[self dismissModalViewControllerAnimated:YES];

I protocolli delegati sono ESTREMAMENTE, ESTREMAMENTE, ESTREMAMENTE utili. Ti farebbe bene familiarizzare con loro :)

NSNotifications è un altro modo per farlo, ma come best practice, preferisco usarlo quando voglio comunicare tra più viewController o oggetti. Ecco una risposta che ho pubblicato in precedenza se sei curioso di utilizzare NSNotifications: Attivazione di eventi su più viewcontroller da un thread nell'appdelegate

MODIFICARE:

Se vuoi passare più argomenti, il codice prima di ignorare ha questo aspetto:

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:argument2:argument3:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!" argument2:someObject argument3:anotherObject];
}
[self dismissModalViewControllerAnimated:YES];

Ciò significa che l'implementazione del metodo SecondDelegate all'interno del firstViewController ora sarà simile a:

- (void) secondViewControllerDismissed:(NSString*)stringForFirst argument2:(NSObject*)inObject1 argument3:(NSObject*)inObject2
{
    NSString thisIsTheDesiredString = stringForFirst;
    NSObject desiredObject1 = inObject1;
    //....and so on
}

Secondo la Guida alla programmazione del controller di visualizzazione di Apple per iOS, il secondViewController dovrebbe essere chiuso nel controller della visualizzazione di presentazione, non in quello presentato.
Michael,

Sembra che tu non abbia impostato il delegato di UITableView. Potresti pubblicare questo come una domanda, con il codice che hai e cerchiare indietro? Potrei essere in grado di aiutarti.
Sid

1
@Michael La documentazione dice che la chiamata a dismiss su self inoltra la chiamata al controller della vista che presenta. Inoltre, la chiamata su se stessi è più pulita in quanto in questo modo non devi preoccuparti di passare da presentationViewController a parentViewController a seconda della versione di iOS a cui ti rivolgi (5 o prima).
Sid

1
@Resty sono d'accordo; i blocchi sono incredibilmente utili. Stavo valutando la possibilità di modificare questa risposta per supportare i blocchi ad un certo punto. Tuttavia, in questo caso, per ora ho lasciato visibile la risposta del delegato perché ci dà un po 'più di libertà di manipolare oggetti che potrebbero essere passati nel modale. Sono solo pigro e aggiornerò presto questa risposta per utilizzare i blocchi :)
Sid

1
@sid grazie fratello funziona per me ma devi leggermente modificare. quante cose sono cambiate. si prega di modificarlo
ChenSmile

40

Potrei essere fuori posto qui, ma sto iniziando a preferire di gran lunga la sintassi del blocco all'approccio molto prolisso delegato / protocollo. Se crei vc2 da vc1, hai una proprietà su vc2 che puoi impostare da vc1 che è un blocco!

@property (nonatomic, copy) void (^somethingHappenedInVC2)(NSString *response);

Quindi, quando accade qualcosa in vc2 di cui vuoi parlare a vc1, esegui semplicemente il blocco che hai definito in vc1!

self.somethingHappenedInVC2(@"Hello!");

Ciò consente di inviare i dati da vc2 a vc1. Proprio come per magia. IMO, questo è molto più facile / pulito dei protocolli. I blocchi sono fantastici e devono essere abbracciati il ​​più possibile.

EDIT - Esempio migliorato

Supponiamo di avere un mainVC su cui vogliamo presentare temporaneamente un modalVC per ottenere un input da un utente. Per presentare quel modalVC da mainVC, dobbiamo allocarlo / iniziarlo all'interno di mainVC. Roba piuttosto semplice. Bene, quando creiamo questo oggetto modalVC, possiamo anche impostare una proprietà di blocco su di esso che ci consente di comunicare facilmente tra entrambi gli oggetti vc. Quindi prendiamo l'esempio dall'alto e mettiamo la seguente proprietà nel file .h di modalVC:

 @property (nonatomic, copy) void (^somethingHappenedInModalVC)(NSString *response);  

Quindi, nel nostro mainVC, dopo aver allocato / inizializzato un nuovo oggetto modalVC, si imposta la proprietà block di modalVC in questo modo:

ModalVC *modalVC = [[ModalVC alloc] init];
modalVC.somethingHappenedInModalVC = ^(NSString *response) {
     NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
}

Quindi stiamo solo impostando la proprietà del blocco e definendo cosa succede quando quel blocco viene eseguito.

Infine, nel nostro modalVC, potremmo avere un tableViewController supportato da un array di stringhe dataSource. Una volta effettuata una selezione di riga, potremmo fare qualcosa del genere:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      NSString *selectedString = self.dataSource[indexPath.row];
      self.somethingHappenedInModalVC(selectedString);
 }

E ovviamente, ogni volta che selezioniamo una riga in modalVC, otterremo un output della console dalla nostra riga NSLog in mainVC. Spero possa aiutare!


1
Dovrebbe funzionare ancora quando si usano gli storyboard? In questo momento non funziona per me. Esce solo con un errore lldb. La differenza principale. Posso vedere che l'allocazione del vc è ora un flusso di storyboard istanziato. EDIT E stavo presentando prima di creare il blocco. Fisso.
malaki1974

2
Sono d'accordo con te :) Ho postato la mia risposta tempo fa. Ora passo dall'uso di blocchi / protocolli a seconda dell'utilizzo. Visto che questo thread è ancora abbastanza attivo fino ad oggi, dovrei, a un certo punto, modificare la mia risposta per includere i blocchi.
Sid

1
Questa risposta deve essere accettata poiché porta la soluzione più intuitiva.
Sukitha Udugamasooriya

2
Delle due risposte appropriate, questa è la migliore!
kygcoleman

1
Questo è di gran lunga il mio metodo preferito. In un batter d'occhio questo viene poi realizzato con chiusure. Molto meglio quindi delegati e notifiche perché non è necessario specificare protocolli o queste costanti di notifica "brutte". Se rendi piacevole il nome della variabile nel vc presentato che contiene la chiusura, può essere un codice molto intuitivo, ad es. Vc.didCancel, vc.didFinish ... Puoi impostarli nel prepareForSegue del vc che lo presenta (se stai usando segues).
HixField

4

hmm, cerca il centro notifiche e restituisci le informazioni in una notifica. ecco che le mele lo prendono - prendo questo approccio personalmente a meno che nessuno abbia altri suggerimenti


Il collegamento in realtà lo complica eccessivamente, tutto ciò che serve è un osservatore (primo View Controller) e inviare la notifica dal secondo. È possibile assegnare selettori a una notifica e ottenere anche le informazioni inviate tramite la notifica.
theiOSDude

2

Definire un protocollo delegato nel secondo controller di visualizzazione e rendere il primo il delegato del secondo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.