web-dev-qa-db-fra.com

rejeterModalViewController ET transmettre des données

J'ai deux contrôleurs de vue, firstViewController et secondViewController. J'utilise ce code pour passer à mon secondViewController (je lui passe également une chaîne):

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

J'utilise ensuite ce code dans secondViewController pour revenir au premier ViewController:

[self dismissModalViewControllerAnimated:YES];

Tout cela fonctionne bien. Ma question est la suivante: comment transmettre des données au premier ViewController? Je voudrais passer une chaîne différente dans le premier ViewController du secondViewController.

84
Andrew Davis

Vous devez utiliser des protocoles délégués ... Voici comment procéder:

Déclarez un protocole dans le fichier d'en-tête de votre secondViewController. Ça devrait ressembler à ça:

#import <UIKit/UIKit.h>

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


@interface SecondViewController : UIViewController
{
    id myDelegate;  
}

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

N'oubliez pas de synthétiser myDelegate dans votre fichier d'implémentation (SecondViewController.m):

@synthesize myDelegate;

Dans le fichier d'en-tête de votre FirstViewController, abonnez-vous au protocole SecondDelegate en procédant comme suit:

#import "SecondViewController.h"

@interface FirstViewController:UIViewController <SecondDelegate>

Maintenant, lorsque vous instanciez SecondViewController dans FirstViewController, vous devez procéder comme suit:

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

Enfin, dans le fichier d'implémentation de votre premier contrôleur de vue (FirstViewController.m), implémentez la méthode SecondDelegate pour secondViewControllerDismissed:

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

Maintenant, lorsque vous êtes sur le point de fermer le deuxième contrôleur de vue, vous souhaitez appeler la méthode implémentée dans le premier contrôleur de vue. Cette partie est simple. Tout ce que vous faites, dans votre deuxième contrôleur de vue, ajoutez du code avant le code de rejet:

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

Les protocoles délégués sont EXTRÊMEMENT, EXTRÊMEMENT, EXTRÊMEMENT utiles. Il serait bon de vous familiariser avec eux :)

NSNotifications est un autre moyen de le faire, mais en tant que meilleure pratique, je préfère l'utiliser lorsque je souhaite communiquer entre plusieurs viewControllers ou objets. Voici une réponse que j'ai postée plus tôt si vous êtes curieux d'utiliser NSNotifications: Déclencher des événements sur plusieurs viewcontrollers à partir d'un thread dans l'appdelegate

MODIFIER:

Si vous souhaitez passer plusieurs arguments, le code avant rejet ressemble à ceci:

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

Cela signifie que votre implémentation de la méthode SecondDelegate dans votre firstViewController ressemblera maintenant à:

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

Je pourrais être hors de propos ici, mais je commence à préférer de beaucoup la syntaxe des blocs à l'approche très verbeuse des délégués/protocoles. Si vous créez vc2 à partir de vc1, ayez une propriété sur vc2 que vous pouvez définir à partir de vc1 qui est un bloc!

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

Ensuite, quand quelque chose se produit dans vc2 dont vous voulez parler à vc1, exécutez simplement le bloc que vous avez défini dans vc1!

self.somethingHappenedInVC2(@"Hello!");

Cela vous permet de renvoyer des données de vc2 vers vc1. Comme par magie. OMI, c'est beaucoup plus facile/plus propre que les protocoles. Les blocs sont impressionnants et doivent être adoptés autant que possible.

EDIT - Exemple amélioré

Disons que nous avons un VC principal que nous voulons présenter temporairement un modalVC pour obtenir des entrées d'un utilisateur. Afin de présenter ce modalVC de mainVC, nous devons l'allouer/l'initier à l'intérieur de mainVC. Des trucs assez basiques. Eh bien, lorsque nous créons cet objet modalVC, nous pouvons également définir une propriété de bloc qui nous permet de communiquer facilement entre les deux objets vc. Prenons donc l'exemple ci-dessus et mettons la propriété follwing dans le fichier .h de modalVC:

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

Ensuite, dans notre mainVC, après avoir alloué/initié un nouvel objet modalVC, vous définissez la propriété block de modalVC comme ceci:

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

Nous définissons donc simplement la propriété du bloc et définissons ce qui se passe lorsque ce bloc est exécuté.

Enfin, dans notre modalVC, nous pourrions avoir un tableViewController qui est soutenu par un tableau dataSource de chaînes. Une fois la sélection de ligne effectuée, nous pourrions faire quelque chose comme ceci:

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

Et bien sûr, chaque fois que nous sélectionnons une ligne dans modalVC, nous allons récupérer une sortie console de notre ligne NSLog dans mainVC. J'espère que ça t'as aidé!

40
Lizza

hmm, recherchez le centre de notification et renvoyez les informations dans une notification. voici les pommes à prendre - Je prends cette approche personnellement à moins que quelqu'un n'ait d'autres suggestions

4
theiOSDude

Définissez un protocole de délégué dans le second contrôleur de vue et faites du premier le délégué du second.

2
cschwarz