Come si configura un delegato semplice per comunicare tra due controller di visualizzazione?


136

Ne ho due UITableViewControllerse devo passare il valore dal controller della vista figlio al genitore usando un delegato. So cosa sono i delegati e volevo solo vedere un esempio semplice da seguire.

Grazie


1
Se si prova il modello Xcode "Utilità", è già implementato un modello delegato. Hai bisogno di più aiuto di quello forse?
phi,

Ecco un tutorial molto semplice. tutorialspoint.com/ios/ios_delegates.htm
Muhammad_Awaab

Risposte:


304

Esempio semplice ...

Supponiamo che il controller di visualizzazione figlio abbia un UISlidere vogliamo restituire il valore del dispositivo di scorrimento al genitore tramite un delegato.

Nel file di intestazione del controller di visualizzazione figlio, dichiarare il tipo delegato e i relativi metodi:

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

Nell'implementazione del controller di visualizzazione figlio, chiamare i metodi delegato come richiesto.

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

Nel file di intestazione del controller della vista padre, dichiarare che implementa il ChildViewControllerDelegateprotocollo.

RootViewController.h

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

@interface RootViewController : UITableViewController <ChildViewControllerDelegate>

@end

Nell'implementazione del controller della vista padre, implementare i metodi delegato in modo appropriato.

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

Spero che questo ti aiuti!


1
In che modo il genitore si registra come delegato del figlio?
Madbreaks

2
Chiamando detailViewController.delegate = self;(è nello -tableView:didSelectRowAtIndexPath:snippet di codice sopra.
Simon Whitaker,

Grazie. Se ChildViewController è delegato a UITableView, dove dovrebbero essere i metodi UITableView? Nel bambino o nel genitore?
Dejell

Ottimo esempio / spiegazione! Sfortunatamente, quando provo a compilare sto ricevendo un errore "Impossibile trovare la dichiarazione del protocollo per" MyProtocol ". È come hai descritto, però: il viewcontroller generato ha la definizione procotol nel suo file .h e invoca il metodo di protocollo nel suo file .m. Il viewcontroller di hosting ha <MyProtocol> nella sua dichiarazione .h @interface - che è dove si verifica l'errore. La tua risposta sembra essere la stessa, però ... qualche idea?
Danny,

Grazie. Ho esaminato almeno una dozzina di risorse e questa è la prima che ho potuto seguire. Penso che i commenti numerati in codice funzionino benissimo per aiutare a spiegarne la sequenza.
JaseC,

32

Questo codice qui sotto mostra solo l'uso basilare del concetto di delegato .. tu dai il nome alla variabile e alla classe secondo il tuo requisito.

Per prima cosa devi dichiarare un protocollo:

Chiamiamolo MyFirstControllerDelegate.h

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

Importa MyFirstControllerDelegate.h di file e confermare la FirstController con protocollo MyFirstControllerDelegate

#import "MyFirstControllerDelegate.h"

@interface FirstController : UIViewController<MyFirstControllerDelegate>
{

}

@end

Nel file di implementazione, è necessario implementare entrambe le funzioni del protocollo:

@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

nel tuo SecondController :

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

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

@end

Nel file di implementazione di SecondController .

@implementation SecondController

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

@end

Ecco l'articolo wiki su delegato.


Mentre questo spiega come impostare un protocollo delegato funzionante. Penso che stia dando alcuni punti chiave. Innanzitutto, quando si chiamano i metodi sul delegato, è necessario innanzitutto verificare che il delegato risponda a quel selettore. In caso contrario, la tua app andrà in crash. In secondo luogo è necessario impostare "@protocol MyFirstControllerDelegate" su @protocol MyFirstControllerDelegate <NSObject>
CW0007007

6

La seguente soluzione è un approccio molto semplice e semplice per inviare dati da VC2 a VC1 usando delegate.

PS: questa soluzione è realizzata in Xcode 9.X e Swift 4

Dichiarato un protocollo e creato un var delegato in 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 conferma il protocollo e prevede di ricevere dati tramite il metodo delegato 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
            }
        }
    }

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.