Comment configurer un délégué simple pour communiquer entre deux contrôleurs de vue?

136

J'en ai deux UITableViewControllerset je dois transmettre la valeur du contrôleur de vue enfant au parent à l'aide d'un délégué. Je sais ce que sont les délégués et je voulais juste voir un exemple simple à suivre.

Merci

jini
la source
1
Si vous essayez le modèle Xcode «Utilitaire», un modèle de délégué est déjà implémenté. Avez-vous besoin de plus d'aide que cela peut-être?
phi
Voici un tutoriel très simple. tutorialspoint.com/ios/ios_delegates.htm
Muhammad_Awaab

Réponses:

304

Exemple simple ...

Disons que le contrôleur de vue enfant a un UISlideret que nous voulons renvoyer la valeur du curseur au parent via un délégué.

Dans le fichier d'en-tête du contrôleur de vue enfant, déclarez le type de délégué et ses méthodes:

ChildViewController.h

#import <UIKit/UIKit.h>

// 1. Forward declaration of ChildViewControllerDelegate - this just declares
// that a ChildViewControllerDelegate type exists so that we can use it
// later.
@protocol ChildViewControllerDelegate;

// 2. Declaration of the view controller class, as usual
@interface ChildViewController : UIViewController

// Delegate properties should always be weak references
// See http://stackoverflow.com/a/4796131/263871 for the rationale
// (Tip: If you're not using ARC, use `assign` instead of `weak`)
@property (nonatomic, weak) id<ChildViewControllerDelegate> delegate;

// A simple IBAction method that I'll associate with a close button in
// the UI. We'll call the delegate's childViewController:didChooseValue: 
// method inside this handler.
- (IBAction)handleCloseButton:(id)sender;

@end

// 3. Definition of the delegate's interface
@protocol ChildViewControllerDelegate <NSObject>

- (void)childViewController:(ChildViewController*)viewController 
             didChooseValue:(CGFloat)value;

@end

Dans l'implémentation du contrôleur de vue enfant, appelez les méthodes déléguées selon les besoins.

ChildViewController.m

#import "ChildViewController.h"

@implementation ChildViewController

- (void)handleCloseButton:(id)sender {
    // Xcode will complain if we access a weak property more than 
    // once here, since it could in theory be nilled between accesses
    // leading to unpredictable results. So we'll start by taking
    // a local, strong reference to the delegate.
    id<ChildViewControllerDelegate> strongDelegate = self.delegate;

    // Our delegate method is optional, so we should 
    // check that the delegate implements it
    if ([strongDelegate respondsToSelector:@selector(childViewController:didChooseValue:)]) {
        [strongDelegate childViewController:self didChooseValue:self.slider.value];
    }
}

@end

Dans le fichier d'en-tête du contrôleur de vue parent, déclarez qu'il implémente le ChildViewControllerDelegateprotocole.

RootViewController.h

#import <UIKit/UIKit.h>
#import "ChildViewController.h"

@interface RootViewController : UITableViewController <ChildViewControllerDelegate>

@end

Dans l'implémentation du contrôleur de vue parent, implémentez les méthodes de délégation de manière appropriée.

RootViewController.m

#import "RootViewController.h"

@implementation RootViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ChildViewController *detailViewController = [[ChildViewController alloc] init];
    // Assign self as the delegate for the child view controller
    detailViewController.delegate = self;
    [self.navigationController pushViewController:detailViewController animated:YES];
}

// Implement the delegate methods for ChildViewControllerDelegate
- (void)childViewController:(ChildViewController *)viewController didChooseValue:(CGFloat)value {

    // Do something with value...

    // ...then dismiss the child view controller
    [self.navigationController popViewControllerAnimated:YES];
}

@end

J'espère que cela t'aides!

Simon Whitaker
la source
1
Mais comment le parent s'enregistre-t-il en tant que délégué de l'enfant?
Madbreaks
2
En appelant detailViewController.delegate = self;(c'est -tableView:didSelectRowAtIndexPath:dans l'extrait de code ci-dessus.
Simon Whitaker
Merci. Si le ChildViewController est délégué à UITableView, où devraient être les méthodes UITableView? Chez l'enfant ou chez le parent?
Dejell
Excellent exemple / explication! Malheureusement, j'obtiens une erreur "Impossible de trouver la déclaration de protocole pour 'MyProtocol'" lorsque j'essaye de compiler. C'est comme vous l'avez décrit, cependant: le viewcontroller généré a la définition procotol dans son fichier .h et invoque la méthode de protocole dans son fichier .m. Le viewcontroller d'hébergement a <MyProtocol> dans sa déclaration .h @interface - c'est là que l'erreur se produit. Votre réponse semble être la même, cependant ... des idées?
Danny
Je vous remercie. J'ai regardé au moins une douzaine de ressources et c'est la première que j'ai pu suivre. Je pense que les commentaires de code numérotés fonctionnent très bien pour aider à expliquer la séquence de celui-ci.
JaseC
32

Ce code ci-dessous montre simplement l'utilisation très basique du concept de délégué .. vous nommez la variable et la classe selon vos besoins.

Vous devez d'abord déclarer un protocole:

Appelons-le MyFirstControllerDelegate.h

@protocol MyFirstControllerDelegate
- (void) FunctionOne: (MyDataOne*) dataOne;
- (void) FunctionTwo: (MyDatatwo*) dataTwo;
@end

Importez le fichier MyFirstControllerDelegate.h et confirmez votre FirstController avec le protocole MyFirstControllerDelegate

#import "MyFirstControllerDelegate.h"

@interface FirstController : UIViewController<MyFirstControllerDelegate>
{

}

@end

Dans le fichier d'implémentation, vous devez implémenter les deux fonctions de protocole:

@implementation FirstController 


    - (void) FunctionOne: (MyDataOne*) dataOne
      {
          //Put your finction code here
      }
    - (void) FunctionTwo: (MyDatatwo*) dataTwo
      {
          //Put your finction code here
      }

     //Call below function from your code
    -(void) CreateSecondController
     {
             SecondController *mySecondController = [SecondController alloc] initWithSomeData:.];
           //..... push second controller into navigation stack 
            mySecondController.delegate = self ;
            [mySecondController release];
     }

@end

dans votre SecondController :

@interface SecondController:<UIViewController>
{
   id <MyFirstControllerDelegate> delegate;
}

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

@end

Dans le fichier d' implémentation de SecondController .

@implementation SecondController

@synthesize delegate;
//Call below two function on self.
-(void) SendOneDataToFirstController
{
   [delegate FunctionOne:myDataOne];
}
-(void) SendSecondDataToFirstController
{
   [delegate FunctionTwo:myDataSecond];
}

@end

Voici l'article wiki sur le délégué.

Jhaliya
la source
Bien que cela couvre comment configurer un protocole de délégué fonctionnel. Je pense que cela omet quelques points clés. Tout d'abord, lorsque vous appelez les méthodes sur le délégué, vous devez d'abord vérifier que le délégué répond à ce sélecteur. Si ce n'est pas le cas, votre application plantera. Deuxièmement, vous devez définir le "@protocol MyFirstControllerDelegate" sur @protocol MyFirstControllerDelegate <NSObject>
CW0007007
6

La solution suivante est une approche très basique et simple pour envoyer des données de VC2 à VC1 à l'aide d'un délégué.

PS: Cette solution est réalisée en Xcode 9.X et Swift 4

Déclarer un protocole et créer une var déléguée dans ViewControllerB

    import UIKit

    //Declare the Protocol into your SecondVC
    protocol DataDelegate {
        func sendData(data : String)
    }

    class ViewControllerB : UIViewController {

    //Declare the delegate property in your SecondVC
        var delegate : DataDelegate?
        var data : String = "Send data to ViewControllerA."
        override func viewDidLoad() {
            super.viewDidLoad()
        }

        @IBAction func btnSendDataPushed(_ sender: UIButton) {
                // Call the delegate method from SecondVC
                self.delegate?.sendData(data:self.data)
                dismiss(animated: true, completion: nil)
            }
        }

ViewControllerA confirme le protocole et devrait recevoir des données via la méthode déléguée sendData

    import UIKit
        // Conform the  DataDelegate protocol in ViewControllerA
        class ViewControllerA : UIViewController , DataDelegate {
        @IBOutlet weak var dataLabel: UILabel!

        override func viewDidLoad() {
            super.viewDidLoad()
        }

        @IBAction func presentToChild(_ sender: UIButton) {
            let childVC =  UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier:"ViewControllerB") as! ViewControllerB
            //Registered delegate
            childVC.delegate = self
            self.present(childVC, animated: true, completion: nil)
        }

        // Implement the delegate method in ViewControllerA
        func sendData(data : String) {
            if data != "" {
                self.dataLabel.text = data
            }
        }
    }
Équipe iOS
la source