Recherche…


Utilisation de Segues (transmission de données en avant)

Pour transmettre des données du contrôleur de vue actuel au nouveau contrôleur de vue suivant (pas à un contrôleur de vue précédent) à l'aide de segues, créez d'abord un lien avec un identifiant dans le storyboard correspondant. Remplacez la méthode prepareForSegue votre contrôleur d'affichage actuel. À l’intérieur de la méthode, vérifiez le segment que vous venez de créer grâce à son identifiant. Lancez le contrôleur de vue de destination et transmettez-lui les données en définissant les propriétés sur le contrôleur de la vue réduite.

Définition d'un identifiant pour un segue:

Inspecteur des attributs pour un segue

Les segues peuvent être exécutées par programme ou en utilisant les actions de bouton définies dans le storyboard par Ctrl + Glisser vers le contrôleur de vue de destination. En cas de besoin, vous pouvez appeler un segue par programme en utilisant l'identifiant de segue dans le contrôleur de vue:

Objectif c

- (void)showDetail {
    [self performSegueWithIdentifier:@"showDetailingSegue" sender:self];        
}

Rapide

func showDetail() {
    self.performSegue(withIdentifier: "showDetailingSegue", sender: self)
}

Vous pouvez configurer la charge utile segue dans la version surchargée de la méthode prepareForSegue . Vous pouvez définir les propriétés requises avant le chargement du contrôleur de vue de destination.

Objectif c

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"showDetailingSegue"]){
        DetailViewController *controller = (DetailViewController *)segue.destinationViewController;
        controller.isDetailingEnabled = YES;
    }
}

Rapide

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetailingSegue" {
        let controller = segue.destinationViewController as! DetailViewController
        controller.isDetailingEnabled = true
    }    
}

DetailViewController est le nom du second contrôleur de vue et isDetailingEnabled est une variable publique dans ce contrôleur de vue.

Pour développer ce modèle, vous pouvez traiter une méthode publique sur DetailViewController tant que pseudo-initialiseur, afin d’initialiser les variables requises. Cela va auto-documenter les variables qui doivent être définies sur DetailViewController sans avoir à lire son code source. C'est aussi un endroit pratique pour mettre des défauts.

Objectif c

- (void)initVC:(BOOL *)isDetailingEnabled {
    self.isDetailingEnabled = isDetailingEnabled
}

Rapide

func initVC(isDetailingEnabled: Bool) {
    self.isDetailingEnabled = isDetailingEnabled
}

Utilisation du modèle de délégué (retour des données)

Pour renvoyer des données du contrôleur de vue actuel au contrôleur de vue précédent, vous pouvez utiliser le modèle de délégué.

entrer la description de l'image ici

Cet exemple suppose que vous avez effectué un segue dans le showSecondViewController interface et que vous définissez l'identificateur de segue sur showSecondViewController . Les points de vente et les actions doivent également être reliés aux noms dans le code suivant.

Premier contrôleur d'affichage

Le code du contrôleur First View est

Rapide

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController", let secondViewController = segue.destinationViewController as? SecondViewController  {
            secondViewController.delegate = self
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    func userDidEnterInformation(info: String) {
        label.text = info
        navigationController?.popViewControllerAnimated(true)
    }
}

Objectif c

@interface FirstViewController : UIViewController <DataEnteredDelegate>
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation FirstViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    SecondViewController *secondViewController = segue.destinationViewController;
    secondViewController.delegate = self;

}
-(void)userDidEnterInformation:(NSString *)info {
    _label.text = info
    [self.navigationController popViewControllerAnimated:YES];
}
@end

Notez l'utilisation de notre protocole personnalisé DataEnteredDelegate .

Second View Controller et Protocole

Le code du second contrôleur de vue est

Rapide

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        // call this method on whichever class implements our delegate protocol (the first view controller)
        delegate?.userDidEnterInformation(textField.text ?? "")
    }
}

Objectif c

@protocol DataEnteredDelegate <NSObject>
-(void)userDidEnterInformation:(NSString *)info;
@end

@interface SecondViewController : UIViewController 
@property (nonatomic) id <DataEnteredDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@end

@implementation SecondViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}

- (IBAction) sendTextBackButton:(id)sender{
    [_delegate userDidEnterInformation:textField.text];
}
@end

Notez que le protocol est en dehors de la classe View Controller.

Passer des données en arrière en utilisant le déroulement pour se

Contrairement à segue qui vous permet de transmettre des données "en avant" du contrôleur de vue actuel au contrôleur de vue de destination:

(VC1) -> (VC2)

En utilisant "dérouler", vous pouvez faire le contraire, passer des données de la destination ou du contrôleur de vue actuel à son contrôleur de vue présentateur:

(VC1) <- (VC2)

REMARQUE : faites attention à ce que l'utilisation de dérouler vous permette de transmettre les données en premier, puis le contrôleur de vue actuel (VC2) sera libéré.

Voici comment procéder:

Tout d'abord, vous devrez ajouter la déclaration suivante au contrôleur de vue de présentation (VC1), qui est le contrôleur de vue que vous souhaitez transmettre aux données:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)

L'important est d'utiliser le préfixe unwind , cela "informe" Xcode qu'il s'agit d'une méthode de déroulage vous donnant la possibilité de l'utiliser également dans le storyboard.

Ensuite, vous devrez implémenter la méthode, elle ressemble presque à un segue réel:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)
{
    if segue.identifier == "YourCustomIdentifer"
    {
        if let VC2 = segue.sourceViewController as? VC2
        {
            //    Your custom code in here to access VC2 class member
        }

Vous avez maintenant 2 options pour appeler les appels à la fin:

  1. Vous pouvez « coder en dur » invoquer le: self.performSegueWithIdentifier("YourCustomIdentifier", sender: self) qui fera le dérouleur pour vous à chaque fois que vous voulez performSegueWithIdentifier .
  2. Vous pouvez lier la méthode de déroulement en utilisant le storyboard à votre objet "Exit": ctrl + faites glisser le bouton que vous voulez appeler la méthode déroulante vers l'objet "Exit":

entrer la description de l'image ici

Relâchez et vous aurez la possibilité de choisir votre méthode de déroulement personnalisée:

entrer la description de l'image ici

Transmission de données à l'aide de fermetures (retour de données)

Au lieu d'utiliser le modèle de délégué , qui divise l'implémentation dans différentes parties de la classe UIViewController , vous pouvez même utiliser des closures pour renvoyer des données en avant et en arrière. En supposant que vous utilisez le UIStoryboardSegue , dans la méthode prepareForSegue , vous pouvez facilement configurer le nouveau contrôleur en une seule étape

final class DestinationViewController: UIViewController {
    var onCompletion: ((success: Bool) -> ())?

    @IBAction func someButtonTapped(sender: AnyObject?) {
        onCompletion?(success: true)
    }
}

final class MyViewController: UIViewController {
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    
        guard let destinationController = segue.destinationViewController as? DestinationViewController else { return }
    
        destinationController.onCompletion = { success in
            // this will be executed when `someButtonTapped(_:)` will be called
            print(success)
        }
    }
}

Ceci est un exemple d'utilisation et il est préférable d'utiliser Swift, la syntaxe du bloc Objective-C n'est pas si facile de rendre le code plus lisible

Utiliser la fermeture de rappel (blocage) pour transmettre des données

ce sujet est un problème classique dans le développement iOS, et sa solution est diverse comme d'autres exemples déjà présentés. Dans cet exemple, je vais vous montrer une autre utilisation quotidienne commune: transmettre des données à l'aide de la closure en adaptant l'exemple de delegate pattern sur cette page en closure rappel!

Une chose que cette méthode est supérieure à delegate pattern est au lieu de diviser le code de configuration en deux endroits différents (regardez l'exemple de délégué sur cette page, prepareForSegue , userDidEnterInformation ) plutôt que de les rassembler (seulement dans prepareForSegue , je le montrerai)

Démarrer à partir de Second View Controller

nous devons comprendre comment utiliser le callback, puis pouvons-nous l'écrire, c'est pourquoi nous commençons à partir du second contrôleur de vue car nous utilisons callback: lorsque nous avons la nouvelle entrée de texte, nous appelons notre callback, en utilisant le paramètre callback comme support pour renvoyer les données au premier ViewController, notez que j'ai dit en utilisant le paramètre callback, c'est très important, les novices (comme je l'étais) oublient toujours cela et ne savent pas par où commencer pour écrire la fermeture de rappel correctement

donc dans ce cas, nous savons que notre callback ne prend qu'un seul paramètre: text et que son type est String , déclarons-le et en faisons la propriété puisque nous avons besoin de remplir notre premier contrôleur de vue

Je ne fais que commenter la partie delegate et la conserver pour la comparer

class SecondViewController: UIViewController {

    //weak var delegate: DataEnteredDelegate? = nil
    var callback: ((String?)->())?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        //delegate?.userDidEnterInformation(textField.text!)
        callback?(input.text)
        
        self.navigationController?.popViewControllerAnimated(true)
    }
}

Terminer le contrôleur de la première vue

tout ce que vous avez à faire est de passer la fermeture de rappel, et nous avons terminé, la fermeture fera le travail futur pour nous puisque nous l'avons déjà configuré dans le contrôleur de deuxième vue

regardez comment cela rend notre code plus court comparé au delegate pattern

//no more DataEnteredDelegate
class FirstViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController as! SecondViewController
            //secondViewController.delegate = self
            secondViewController.callback = { text in self.label.text = text }
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    //func userDidEnterInformation(info: String) {
    //    label.text = info
    //}
}

et dans le dernier cas, peut-être quelqu'un d'entre vous sera-t-il confus en pensant que nous ne transmettons que les données (fermeture dans ce cas) d'une seule manière, considère-le comme un outil de communication? peut-être devriez-vous vraiment l'exécuter et le prouver vous-même, tout ce que je dirai, c'est le paramètre , c'est le paramètre de la fermeture de rappel qui renvoie les données!

En attribuant une propriété (transmission de données vers l'avant)

Vous pouvez transmettre des données directement en assignant la propriété du contrôleur de vue suivant avant de le pousser ou de le présenter.

class FirstViewController: UIViewController {

    func openSecondViewController() {

        // Here we initialize SecondViewController and set the id property to 492
        let secondViewController = SecondViewController()
        secondViewController.id = 492

        // Once it was assign we now push or present the view controller
        present(secondViewController, animated: true, completion: nil)
    }

}

class SecondViewController: UIViewController {
    
    var id: Int?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Here we unwrapped the id and will get the data from the previous view controller.
        if let id = id {
            print("Id was set: \(id)")
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow