entlassenModalViewController UND Daten zurückgeben

84

Ich habe zwei View Controller, firstViewController und secondViewController . Ich verwende diesen Code, um zu meinem zweiten ViewController zu wechseln (ich übergebe ihm auch eine Zeichenfolge):

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

Ich verwende diesen Code dann in secondViewController, um zum firstViewController zurückzukehren:

[self dismissModalViewControllerAnimated:YES];

All dies funktioniert gut. Meine Frage ist, wie würde ich Daten an den firstViewController übergeben? Ich möchte eine andere Zeichenfolge als der zweite ViewController an den firstViewController übergeben.

Andrew Davis
quelle

Antworten:

142

Sie müssen Delegate-Protokolle verwenden ... So geht's:

Deklarieren Sie ein Protokoll in der Header-Datei Ihres secondViewController. Es sollte so aussehen:

#import <UIKit/UIKit.h>

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


@interface SecondViewController : UIViewController
{
    id myDelegate;  
}

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

Vergessen Sie nicht, das myDelegate in Ihrer Implementierungsdatei (SecondViewController.m) zu synthetisieren:

@synthesize myDelegate;

Abonnieren Sie in der Header-Datei Ihres FirstViewController das SecondDelegate-Protokoll folgendermaßen:

#import "SecondViewController.h"

@interface FirstViewController:UIViewController <SecondDelegate>

Wenn Sie jetzt SecondViewController in FirstViewController instanziieren, sollten Sie Folgendes tun:

// 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];

Zuletzt implementieren Sie in der Implementierungsdatei für Ihren First View Controller (FirstViewController.m) die SecondDelegate-Methode für secondViewControllerDismissed:

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

Wenn Sie nun den zweiten Ansichts-Controller schließen möchten, möchten Sie die im ersten Ansichts-Controller implementierte Methode aufrufen. Dieser Teil ist einfach. Alles, was Sie tun, ist, in Ihrem zweiten Ansichts-Controller vor dem Entlassungscode einen Code hinzuzufügen:

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

Delegate-Protokolle sind EXTREM, EXTREM, EXTREM nützlich. Es würde dir gut tun, dich mit ihnen vertraut zu machen :)

NSNotifications sind eine weitere Möglichkeit, dies zu tun. Als bewährte Methode bevorzuge ich die Verwendung, wenn ich über mehrere viewController oder Objekte hinweg kommunizieren möchte. Hier ist eine Antwort, die ich zuvor gepostet habe, wenn Sie neugierig auf die Verwendung von NSNotifications sind: Auslösen von Ereignissen über mehrere Viewcontroller aus einem Thread in der Appdelegate

BEARBEITEN:

Wenn Sie mehrere Argumente übergeben möchten, sieht der Code vor dem Entlassen folgendermaßen aus:

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

Dies bedeutet, dass Ihre Implementierung der SecondDelegate-Methode in Ihrem firstViewController nun wie folgt aussieht:

- (void) secondViewControllerDismissed:(NSString*)stringForFirst argument2:(NSObject*)inObject1 argument3:(NSObject*)inObject2
{
    NSString thisIsTheDesiredString = stringForFirst;
    NSObject desiredObject1 = inObject1;
    //....and so on
}
Sid
quelle
Laut Apples View Controller-Programmierhandbuch für iOS sollte der zweite ViewController im präsentierenden View Controller und nicht im präsentierten deaktiviert werden.
Michael
Klingt so, als hätten Sie den Delegierten von UITableView nicht festgelegt. Könnten Sie dies als Frage mit dem Code, den Sie haben, posten und zurückkreisen? Ich könnte Ihnen vielleicht helfen.
Sid
1
@Michael In der Dokumentation heißt es, dass der Aufruf "Entlassen bei Selbst" den Anruf an den präsentierenden Ansichts-Controller weiterleitet. Außerdem ist es sauberer, sich selbst anzurufen, da Sie sich nicht darum kümmern müssen, je nach der iOS-Version, auf die Sie abzielen (5 oder früher), zwischen PresentingViewController und ParentViewController zu wechseln.
Sid
1
@Resty Ich stimme zu; Blöcke sind erstaunlich nützlich. Ich dachte darüber nach, diese Antwort irgendwann in Unterstützungsblöcke zu ändern. In diesem Fall habe ich die Antwort des Delegierten jedoch vorerst sichtbar gelassen, da wir dadurch etwas mehr Freiheit haben, Objekte zu manipulieren, die an das Modal übergeben werden könnten. Ich bin nur faul und werde diese Antwort aktualisieren, um bald Blöcke zu verwenden :)
Sid
1
@sid danke bro es funktioniert für mich aber du musst etwas modifizieren. so viele Dinge haben sich geändert. Bitte bearbeiten Sie es
ChenSmile
40

Ich könnte hier weit weg sein, aber ich fange an, die Blocksyntax dem sehr ausführlichen Delegaten- / Protokollansatz vorzuziehen. Wenn Sie vc2 aus vc1 erstellen, haben Sie eine Eigenschaft auf vc2, die Sie aus vc1 festlegen können, die ein Block ist!

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

Wenn dann in vc2 etwas passiert, von dem Sie vc1 erzählen möchten, führen Sie einfach den Block aus, den Sie in vc1 definiert haben!

self.somethingHappenedInVC2(@"Hello!");

Auf diese Weise können Sie Daten von VC2 zurück an VC1 senden. Genau wie Magie. IMO, das ist viel einfacher / sauberer als Protokolle. Blöcke sind fantastisch und müssen so weit wie möglich umarmt werden.

EDIT - Verbessertes Beispiel

Angenommen, wir haben eine Haupt-VC, auf der wir vorübergehend eine modale VC präsentieren möchten, um Eingaben von einem Benutzer zu erhalten. Um diese modalVC von mainVC zu präsentieren, müssen wir sie innerhalb von mainVC zuweisen / initiieren. Ziemlich einfaches Zeug. Wenn wir dieses modalVC-Objekt erstellen, können wir auch eine Blockeigenschaft festlegen, mit der wir problemlos zwischen beiden VC-Objekten kommunizieren können. Nehmen wir also das Beispiel von oben und fügen Sie die folgende Eigenschaft in die .h-Datei von modalVC ein:

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

Nachdem Sie in unserer mainVC ein neues modalVC-Objekt zugewiesen / initialisiert haben, legen Sie die Blockeigenschaft von modalVC folgendermaßen fest:

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

Wir setzen also nur die Blockeigenschaft und definieren, was passiert, wenn dieser Block ausgeführt wird.

Schließlich könnten wir in unserer modalVC einen tableViewController haben, der von einem dataSource-Array von Zeichenfolgen unterstützt wird. Sobald eine Zeilenauswahl getroffen ist, können wir Folgendes tun:

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

Und natürlich erhalten wir jedes Mal, wenn wir eine Zeile in modalVC auswählen, eine Konsolenausgabe von unserer NSLog-Zeile zurück in mainVC. Hoffentlich hilft das!

Lizza
quelle
1
Sollte dies bei Verwendung von Storyboards noch funktionieren? Im Moment funktioniert es nicht für mich. Beendet einfach mit einem lldb-Fehler. Der Hauptunterschied Ich kann sehen, dass die Zuweisung des VC jetzt ein instanziierter Storyboard-Flow ist. BEARBEITEN Und ich präsentierte vor dem Erstellen des Blocks. Fest.
Malaki1974
2
Ich stimme dir zu :) Ich habe meine Antwort vor einiger Zeit gepostet. Jetzt wechsle ich je nach Verwendung zwischen der Verwendung von Blöcken / Protokollen. Da dieser Thread bis heute noch ziemlich aktiv ist, sollte ich meine Antwort irgendwann so bearbeiten, dass sie Blöcke enthält.
Sid
1
Diese Antwort muss akzeptiert werden, da dies die intuitivste Lösung bietet.
Sukitha Udugamasooriya
2
Von den beiden passenden Antworten ist dies die beste!
Kygcoleman
1
Dies ist bei weitem meine bevorzugte Methode. In kurzer Zeit wird dies dann mit Verschlüssen erreicht. Viel besser als Delegierte und Benachrichtigungen, da Sie keine Protokolle oder diese "hässlichen" Benachrichtigungskonstanten angeben müssen. Wenn Sie den Namen der Variablen in der dargestellten VC machen, die den Abschluss schön hält, kann dies ein sehr intuitiver Code sein, z. Vc.didCancel, vc.didFinish ... Sie können diese in der prepareForSegue für die vc festlegen, die sie präsentiert (wenn Sie Segues verwenden).
HixField
4

hmm, suchen Sie nach dem Benachrichtigungscenter und geben Sie Informationen in einer Benachrichtigung zurück. Hier ist Äpfel übernehmen - ich gehe persönlich vor, es sei denn, jemand hat andere Vorschläge

theiOSDude
quelle
Der Link macht es tatsächlich zu kompliziert. Sie benötigen lediglich einen Beobachter (erster View Controller) und senden die Benachrichtigung vom zweiten. Sie können einer Benachrichtigung Selektoren zuweisen und die Informationen auch über die Benachrichtigung zurücksenden.
theiOSDude
2

Definieren Sie ein Delegatenprotokoll im zweiten Ansichtscontroller und machen Sie das erste zum Delegaten des zweiten.

cschwarz
quelle