web-dev-qa-db-fra.com

Passage de données entre les contrôleurs de vue

Je suis nouveau dans iOS, Objective-C et dans tout le paradigme de MVC et je suis coincé avec ce qui suit:

J'ai une vue qui agit comme un formulaire de saisie de données et je veux donner à l'utilisateur la possibilité de sélectionner plusieurs produits. Les produits sont répertoriés dans une autre vue avec une variable UITableViewController et j'ai activé plusieurs sélections.

Ma question est la suivante: comment transférer les données d'un point de vue à un autre? Je maintiendrai les sélections sur la UITableView dans un tableau, mais comment puis-je le transmettre à la vue précédente du formulaire de saisie de données afin qu'il puisse être enregistré avec les autres données dans Core Data lors de la soumission du formulaire?

J'ai surfé et vu certaines personnes déclarer un tableau dans le délégué de l'application. J'ai lu quelque chose sur Singletons mais je ne comprends pas ce que c'est et j'ai lu quelque chose sur la création d'un modèle de données.

Quelle serait la bonne façon de procéder et comment pourrais-je m'y prendre?

1254
Matt Price

Cette question semble être très populaire ici sur stackoverflow, alors je me suis dit que j'essaierais de donner une meilleure réponse pour aider les personnes débutant dans le monde d'iOS comme moi.

J'espère que cette réponse est suffisamment claire pour que les gens comprennent et que je n'ai rien manqué.

Passing Data Forward

Transmission de données à un contrôleur de vue à partir d'un autre contrôleur de vue. Vous utiliseriez cette méthode si vous souhaitez transmettre un objet/une valeur d'un contrôleur de vue à un autre contrôleur de vue sur lequel vous souhaitez éventuellement appuyer sur une pile de navigation.

Pour cet exemple, nous aurons ViewControllerA et ViewControllerB

Pour passer une valeur BOOL de ViewControllerA à ViewControllerB, procédez comme suit.

  1. dans ViewControllerB.h créer une propriété pour la BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. dans ViewControllerA vous devez parler de ViewControllerB alors utilisez un 

    #import "ViewControllerB.h"
    

    Puis où vous voulez charger la vue par exemple. didSelectRowAtIndex ou un certain IBAction vous devez définir la propriété dans ViewControllerB avant de le placer dans la pile de navigation.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    

    Ceci définira isSomethingEnabled dans ViewControllerB à BOOL valeur YES.

Passing Data Forward avec Segues

Si vous utilisez les Storyboards, vous utilisez probablement des segments et vous aurez besoin de cette procédure pour transmettre les données. Ceci est similaire à ce qui précède, mais au lieu de transmettre les données avant de pousser le contrôleur de vue, vous utilisez une méthode appelée

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

Donc, pour passer une BOOL de ViewControllerA à ViewControllerB, nous ferions ce qui suit:

  1. dans ViewControllerB.h créer une propriété pour la BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. dans ViewControllerA vous devez parler de ViewControllerB alors utilisez un

    #import "ViewControllerB.h"
    
  3. Créez une séquence de ViewControllerA à ViewControllerB sur le storyboard et attribuez-lui un identifiant. Dans cet exemple, nous l'appellerons "showDetailSegue"

  4. Ensuite, nous devons ajouter la méthode à ViewControllerA qui est appelée lorsqu’une séquence est exécutée. Pour cette raison, nous devons détecter quelle séquence a été appelée, puis faire quelque chose. Dans notre exemple, nous vérifierons "showDetailSegue" et si cela est exécuté, nous passerons notre valeur BOOL à ViewControllerB

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

    Si vos vues sont incorporées dans un contrôleur de navigation, vous devez modifier légèrement la méthode ci-dessus en procédant comme suit:

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    Ceci définira isSomethingEnabled dans ViewControllerB à BOOL valeur YES.

Passing Data Back

Pour transmettre des données de ViewControllerB à ViewControllerA, vous devez utiliser Protocoles et délégués ou Blocs, ce dernier peut être utilisé comme mécanisme à couplage lâche pour les rappels.

Pour ce faire, nous ferons de ViewControllerA un délégué de ViewControllerB. Cela permet à ViewControllerB de renvoyer un message à ViewControllerA, ce qui nous permet de renvoyer des données.

Pour que ViewControllerA soit un délégué de ViewControllerB, il doit être conforme au protocole de ViewControllerB que nous devons spécifier. Ceci indique à ViewControllerA les méthodes à implémenter.

  1. Dans ViewControllerB.h, sous le #import, mais au dessus de @interface, vous spécifiez le protocole.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. next toujours dans le ViewControllerB.h vous devez configurer une propriété delegate et synthétiser dans ViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. Dans ViewControllerB, nous appelons un message sur la delegate lorsque nous ouvrons le contrôleur de vue.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. C'est tout pour ViewControllerB. Maintenant, dans ViewControllerA.h, dites à ViewControllerA d'importer ViewControllerB et de vous conformer à son protocole.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  5. Dans ViewControllerA.m implémentez la méthode suivante de notre protocole

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. Avant de placer viewControllerB dans la pile de navigation, nous devons dire à ViewControllerB que ViewControllerA est son délégué, sinon nous obtiendrons une erreur.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];
    

Références

  1. Utilisation de la délégation pour communiquer avec d'autres contrôleurs de vue dans le Guide de programmation de View Controller
  2. Modèle délégué

NSNotification Center C'est un autre moyen de transmettre des données. 

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

Transmission de données d'une classe à une autre (une classe peut être n'importe quel contrôleur, gestionnaire de réseau/de session, sous-classe UIView ou toute autre classe)

Les blocs sont des fonctions anonymes.

Cet exemple transmet des données de Controller B à Controller A

définir un bloc

@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h

add block handler (listener) où vous avez besoin d'une valeur (par exemple, vous avez besoin de votre réponse d'API dans ControllerA ou vous avez besoin de données ContorllerB sur A)

// in ContollerA.m

- (void)viewDidLoad {
    [super viewDidLoad];
    __unsafe_unretained typeof(self) weakSelf = self;
    self.selectedVoucherBlock = ^(NSString *voucher) {
        weakSelf->someLabel.text = voucher;
    };
}

Aller au contrôleur B

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
    [self.navigationController pushViewController:vc animated:NO];

bloc de feu

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: 
(NSIndexPath *)indexPath {
    NSString *voucher = vouchersArray[indexPath.row];
    if (sourceVC.selectVoucherBlock) {
        sourceVC.selectVoucherBlock(voucher);
    }
    [self.navigationController popToViewController:sourceVC animated:YES];
}

Un autre exemple de travail pour les blocs

1599
Matt Price

Rapide

Il y a des tonnes d'explications ici et autour de StackOverflow, mais si vous êtes un débutant et que vous voulez juste faire fonctionner quelque chose de base, essayez de regarder ce tutoriel sur YouTube (c'est ce qui m'a permis de enfin comprendre comment le faire).

Transmission de données au prochain contrôleur de vue

Voici un exemple basé sur la vidéo. L'idée est de transmettre une chaîne du champ de texte du premier contrôleur de vue à l'étiquette du deuxième contrôleur de vue.

enter image description here

Créez la mise en page du storyboard dans Interface Builder. Pour faire la transition, il suffit de Control cliquez sur le bouton et faites-le glisser vers le contrôleur de deuxième vue.

Premier contrôleur de vue

Le code pour le premier contrôleur de vue est

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // get a reference to the second view controller
        let secondViewController = segue.destination as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

Second View Controller

Et le code pour le contrôleur de deuxième vue est

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

N'oubliez pas

  • Connectez les prises pour UITextFieldet UILabelname__.
  • Définissez les premier et second contrôleurs de vue sur les fichiers Swift appropriés dans IB.

Retour des données au précédent View Controller

Pour transmettre les données du second contrôleur de vue au premier, vous utilisez n protocole et un délégué . Cette vidéo est un aperçu très clair de ce processus:

Voici un exemple basé sur la vidéo (avec quelques modifications).

enter image description here

Créez la mise en page du storyboard dans Interface Builder. Encore une fois, pour faire la transition, vous venez Control glisser du bouton vers le second contrôleur de vue. Définissez l'identificateur de segment sur showSecondViewControllername__. De plus, n'oubliez pas de connecter les prises et les actions en utilisant les noms dans le code suivant.

Premier contrôleur de vue

Le code pour le premier contrôleur de vue est

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

Notez l'utilisation de notre protocole personnalisé DataEnteredDelegatename__.

Contrôleur et protocole Second View

Le code du second contrôleur de vue est

import UIKit

// 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? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

Notez que protocolest en dehors de la classe View Controller.

C'est tout. En exécutant l'application maintenant, vous devriez pouvoir renvoyer des données du deuxième contrôleur de vue au premier.

164
Suragch

Le M dans MVC est pour "Model" et dans le paradigme MVC, le rôle des classes de modèle est de gérer les données d'un programme. Un modèle est l'opposé d'une vue: une vue sait comment afficher des données, mais elle ne sait pas quoi faire des données, alors qu'un modèle sait tout sur la façon de travailler avec les données, mais rien sur la façon de les afficher. Les modèles peuvent être compliqués, mais ils ne doivent pas l'être: le modèle de votre application peut être aussi simple qu'un tableau de chaînes ou de dictionnaires.

Le rôle du contrôleur est d’intervenir entre vue et modèle. Par conséquent, ils ont besoin d'une référence à un ou plusieurs objets de vue et à un ou plusieurs objets de modèle. Disons que votre modèle est un tableau de dictionnaires, chaque dictionnaire représentant une ligne de votre table. La vue racine de votre application affiche cette table et peut être chargée du chargement du tableau à partir d'un fichier. Lorsque l'utilisateur décide d'ajouter une nouvelle ligne à la table, il appuie sur un bouton et votre contrôleur crée un nouveau dictionnaire (modifiable) et l'ajoute au tableau. Afin de remplir la ligne, le contrôleur crée un contrôleur de vue de détail et lui donne le nouveau dictionnaire. Le contrôleur de vue de détail remplit le dictionnaire et renvoie. Le dictionnaire fait déjà partie du modèle, il n’ya rien d’autre à faire.

122
Caleb

Les données peuvent être reçues de différentes manières dans iOS. Par exemple - 

  1. Initialisation directe après l'affectation d'une autre classe.
  2. Délégation - pour la transmission des données 
  3. Notification - pour la diffusion de données à plusieurs classes en même temps
  4. Enregistrement dans NSUserDefaults - pour y accéder plus tard
  5. Cours singleton 
  6. Bases de données et autres mécanismes de stockage tels que plist, etc.

Mais pour le simple scénario consistant à transmettre une valeur à une classe différente dont l’affectation est effectuée dans la classe actuelle, la méthode la plus courante et préférée serait la définition directe de valeurs après l’affectation. Cela se fait comme suit:-

Nous pouvons le comprendre en utilisant deux contrôleurs - Controller1 et Controller2  

Supposons que dans la classe Controller1 vous voulez créer l'objet Controller2 et le pousser avec une valeur de chaîne en cours de transmission. Cela peut être fait comme ceci: -

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj passValue:@"String"];
    [self pushViewController:obj animated:YES];
}

Dans l’implémentation de la classe Controller2, cette fonction sera utilisée. 

@interface Controller2  : NSObject

@property (nonatomic , strong) NSString* stringPassed;

@end

@implementation Controller2

@synthesize stringPassed = _stringPassed;

- (void) passValue:(NSString *)value {

    _stringPassed = value; //or self.stringPassed = value
}

@end

Vous pouvez également définir directement les propriétés de la classe Controller2 de la manière suivante:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj setStringPassed:@"String"];  
    [self pushViewController:obj animated:YES];
}

Pour transmettre plusieurs valeurs, vous pouvez utiliser plusieurs paramètres tels que: -

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1” andValues:objArray withDate:date]; 

Ou, si vous devez transmettre plus de 3 paramètres liés à une fonctionnalité commune, vous pouvez stocker les valeurs dans une classe Model et transmettre ce modelObject à la classe suivante.

ModelClass *modelObject = [[ModelClass alloc] init]; 
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];

Si bref si vous voulez -

1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.

J'espère que cela t'aides

87
borncrazy

Après plus de recherches, il nous a semblé que Protocols and Delegates était le moyen correct/préféré de Apple de le faire.

J'ai fini par utiliser cet exemple

Partage de données entre les contrôleurs de vue et d'autres objets @ iPhone Dev SDK

A bien fonctionné et m'a permis de passer une chaîne et un tableau en avant et en arrière entre mes vues.

Merci pour votre aide

78
Matt Price

Je trouve la version la plus simple et la plus élégante avec des blocs qui passent .. __ Nomons le contrôleur de vue qui attend les données renvoyées en tant que "A" et le contrôleur de vue renvoyant en tant que "B". Dans cet exemple, nous voulons obtenir 2 valeurs: première de Type1 et seconde de Type2.

En supposant que nous utilisons Storyboard, le premier contrôleur définit le blocage des rappels, par exemple lors de la préparation de la séquence:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

et le contrôleur de vue "B" doit déclarer la propriété de rappel, BViewController.h:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

Ensuite, dans le fichier d'implémentation BViewController.m, après que nous ayons souhaité que les valeurs renvoient, notre rappel doit s'appeler

if (self.callback)
    self.callback(value1, value2);

Une chose à garder à l'esprit est que l'utilisation de bloc nécessite souvent de gérer des références fortes et __weakes comme expliqué ici

61
Leszek Zarna

Beaucoup de réponses contiennent de bonnes informations, mais aucune n’adresse la question de manière exhaustive.

La question concerne la transmission d'informations entre contrôleurs de vue. L'exemple spécifique donné concerne la transmission d'informations entre vues, mais compte tenu de la nouveauté déclarée par iOS, l'affiche originale signifiait probablement entre viewControllers, pas entre vues (sans aucune implication des ViewControllers). Il semble que toutes les réponses se concentrent sur deux contrôleurs de vue, mais que faire si l'application évolue pour impliquer plus de deux contrôleurs de vue dans l'échange d'informations? 

L’affiche originale a également posé des questions sur Singletons et l’utilisation de AppDelegate. Il faut répondre à ces questions.

Pour aider ceux qui ont une réponse complète à cette question et qui veulent une réponse complète, je vais essayer de la fournir.

Scénarios d'application

Plutôt que d'avoir une discussion abstraite hautement hypothétique, il est utile d'avoir à l'esprit des applications concrètes. Pour aider à définir une situation de contrôleur à deux vues et une situation de contrôleur à plus de deux vues, je vais définir deux scénarios d'application concrets.

Scénario 1: Deux contrôleurs de vue au maximum ont besoin de partager des informations ..__ Voir diagramme 1. 

diagram of original problem

Il existe deux contrôleurs de vue dans l'application. Il existe un ViewControllerA (Formulaire de saisie de données) et un View Controller B (Liste de produits). Les éléments sélectionnés dans la liste de produits doivent correspondre aux éléments affichés dans la zone de texte du formulaire de saisie. Dans ce scénario, ViewControllerA et ViewControllerB doivent communiquer directement entre eux et aucun autre contrôleur de vue. 

Scénario deux: plus de deux contrôleurs de vue doivent partager les mêmes informations ..__ Voir diagramme deux.

home inventory application diagram

Il y a quatre contrôleurs de vue dans l'application. Il s’agit d’une application à onglets permettant de gérer l’inventaire du domicile. Trois contrôleurs de vues présentent des vues filtrées différemment des mêmes données:

  • ViewControllerA - Articles de luxe 
  • ViewControllerB - Articles non assurés
  • ViewControllerC - Inventaire complet pour la maison 
  • ViewControllerD - Ajouter un nouveau formulaire d'article

Chaque fois qu'un élément individuel est créé ou modifié, il doit également être synchronisé avec les autres contrôleurs de vue. Par exemple, si nous ajoutons un bateau dans ViewControllerD, mais que celui-ci n’est pas encore assuré, le bateau doit apparaître lorsque l’utilisateur accède à ViewControllerA (Articles de luxe) et à ViewControllerC (Inventaire résidentiel complet), mais pas lorsque l’utilisateur accède à ViewControllerB (Articles non assurés). Nous devons nous préoccuper non seulement de l’ajout de nouveaux éléments, mais également de la suppression d’éléments (pouvant être autorisés à partir de l’un des quatre contrôleurs de vue), ou de la modification d’éléments existants (pouvant être autorisés à partir du "Ajouter un nouveau formulaire d’article", en les réutilisant). pour l'édition).

Étant donné que tous les contrôleurs de vue doivent partager les mêmes données, les quatre contrôleurs de vue doivent rester synchronisés. Par conséquent, il doit exister une sorte de communication avec tous les autres contrôleurs de vue, chaque fois qu'un seul contrôleur de vue modifie les données sous-jacentes. Il devrait être assez évident que nous ne voulons pas que chaque contrôleur de vue communique directement entre eux dans ce scénario. Au cas où cela ne serait pas évident, demandez-vous si nous avions 20 contrôleurs de vue différents (au lieu de 4). Dans quelle mesure serait-il difficile et source d'erreurs d'avertir chacun des 19 autres contrôleurs de vue à chaque fois qu'un contrôleur de vue effectuait une modification?

Les solutions: les délégués et le modèle d'observateur, et les singletons

Dans le scénario 1, nous avons plusieurs solutions viables, d’autres réponses ayant donné

  • segues
  • les délégués
  • définition des propriétés sur les contrôleurs de vue directement
  • NSUserDefaults (en fait un mauvais choix)

Dans le deuxième scénario, nous avons d’autres solutions viables:

  • Modèle d'observateur 
  • Singletons

Un singleton est une instance d'une classe, cette instance étant la seule instance existant au cours de son existence. Un singleton tire son nom du fait qu'il s'agit d'une instance unique. Normalement, les développeurs qui utilisent des singletons disposent de méthodes de classe spéciales pour y accéder. 

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

Maintenant que nous comprenons ce qu'est un singleton, discutons de son insertion dans le modèle d'observateur. Le modèle d'observateur est utilisé pour qu'un objet réponde aux modifications apportées par un autre objet. Dans le deuxième scénario, nous avons quatre contrôleurs de vue différents, qui souhaitent tous être informés des modifications apportées aux données sous-jacentes. Les "données sous-jacentes" doivent appartenir à une seule instance, un singleton. Le "savoir sur les changements" est accompli en observant les changements apportés au singleton.L'application d'inventaire domestique aurait une seule instance d'une classe conçue pour gérer une liste d'éléments d'inventaire. Le gestionnaire gérerait une collection d'articles ménagers. Voici une définition de classe pour le gestionnaire de données:.

#import <Foundation/Foundation.h> @class JGCHouseholdInventoryItem; @interface HouseholdInventoryManager : NSObject /*! The global singleton for accessing application data */ + (HouseholdInventoryManager*) sharedManager; - (NSArray *) entireHouseholdInventory; - (NSArray *) luxuryItems; - (NSArray *) nonInsuredItems; - (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item; - (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item; - (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item; @end

  • NSNotificationCenter.
  • Dans le deuxième scénario, nous n'avons pas une propriété unique de HouseholdInventoryManager qui pourrait être observée à l'aide de KVO. Comme nous n'avons pas une seule propriété facilement observable, le modèle d'observateur, dans ce cas, doit être implémenté à l'aide de NSNotificationCenter. Chacun des quatre contrôleurs de vue souscrirait à des notifications, et sharedManager enverrait des notifications au centre de notification le cas échéant. Le gestionnaire d'inventaire n'a pas besoin de savoir quoi que ce soit sur les contrôleurs de vue ni sur les instances d'autres classes susceptibles d'être intéressées par le moment où la collection d'éléments d'inventaire change; NSNotificationCenter s'occupe de ces détails d'implémentation. Les contrôleurs de vue s'abonnent simplement aux notifications et le gestionnaire de données ne fait que poster des notifications.

Beaucoup de programmeurs débutants profitent du fait qu'il y a toujours exactement un Application Delegate dans la vie de l'application, qui est accessible de manière globale. Les programmeurs débutants utilisent ce fait pour insérer des objets et des fonctionnalités dans appDelegate afin de faciliter l'accès depuis n'importe où dans l'application. Ce n'est pas parce que l'AppDelegate est un singleton qu'il devrait remplacer tous les autres singletons. Cette pratique est médiocre car elle impose un fardeau trop lourd à une classe et enfreint les bonnes pratiques orientées objet. Chaque classe doit avoir un rôle clair qui s’explique facilement, souvent par le nom de la classe.

Chaque fois que votre délégué aux applications commence à être gonflé, commencez à supprimer les fonctionnalités des singletons. Par exemple, la pile de données principale ne doit pas être laissée dans AppDelegate, mais doit plutôt être placée dans sa propre classe, une classe coreDataManager.

Références 

50
Jason Cross

Renvoyer des données de ViewController 2(destination) à viewController 1(Source) est la chose la plus intéressante . En supposant que vous utilisiez storyBoard, ce sont tous les moyens que j'ai découverts:

  • Déléguer 
  • Notification
  • Valeurs utilisateur
  • Singleton

Celles-ci ont déjà été discutées ici.

J'ai trouvé qu'il y a plus de moyens:

-Utilisation de rappels de bloc:

utilisez-le dans la méthode prepareForSegue dans le VC1

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

-Utilisation de storyboards Unwind (Exit)

Implémentez une méthode avec un argument UIStoryboardSegue dans VC 1, comme celui-ci:

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

Dans le storyBoard, reliez le bouton "retour" au bouton vert Exit (Unwind) de vc . Vous avez maintenant une séquence qui "revient en arrière" afin que vous puissiez utiliser la propriété DestinationViewController dans le prepareForSegue de VC2 et que Modifie toute propriété de VC1 avant son retour.

  • Une autre option consiste à utiliser les storyboards Undwind (Exit) - vous pouvez utiliser la méthode que vous avez écrite dans VC1.

    -(IBAction)UnWindDone:(UIStoryboardSegue *)segue {
        NextViewController *nextViewController = segue.sourceViewController;
        self.unwindLabel.text = nextViewController.unwindPropertyPass;
    } 
    

    Et dans le prepareForSegue de VC1, vous pouvez modifier n’importe quelle propriété que vous souhaitez partager.

Dans les deux options de déroulement, vous pouvez définir la propriété de balise du bouton et l'enregistrer le prepareForSegue. 

J'espère avoir ajouté quelque chose à la discussion. 

:) À votre santé.

38
Yevgeni

Il existe plusieurs méthodes pour partager des données.

  1. Vous pouvez toujours partager des données en utilisant NSUserDefaults. Définissez la valeur que vous souhaitez partager par rapport à une clé de votre choix et obtenez la valeur de NSUserDefault associée à cette clé dans le prochain contrôleur de vue. 

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
    
  2. Vous pouvez simplement créer une propriété dans viewcontrollerA. Créez un objet de viewcontrollerA dans viewcontrollerB et affectez la valeur souhaitée à cette propriété.

  3. Vous pouvez également créer des délégués personnalisés pour cela.

37
Anubrata Santra

L’opérateur n’a pas mentionné les contrôleurs de vue, mais de nombreuses réponses le font, et j’ai voulu préciser ce que certaines des nouvelles fonctionnalités de la LLVM permettent de rendre cela plus facile lorsque l’on souhaite transférer des données d’un contrôleur de vue à un autre, puis de nouveau. obtenir des résultats en retour.

Les séquences de story-board, les blocs ARC et LLVM rendent cela plus facile que jamais pour moi. Certaines des réponses ci-dessus mentionnent déjà des storyboards et des segments, mais reposent toujours sur la délégation. Définir des délégués fonctionne certes, mais certaines personnes peuvent trouver plus facile de passer des pointeurs ou des blocs de code.

Avec UINavigators et segues, il existe des moyens simples de transmettre des informations au contrôleur sous-serveur et de les récupérer. ARC facilite le passage de pointeurs vers des éléments dérivés de NSObjects. Par conséquent, si vous souhaitez que le contrôleur sous-serveur ajoute/modifie/modifie certaines données, transmettez-le à une instance mutable. Les blocs facilitent les actions de passage. Si vous souhaitez que le contrôleur sous-serveur appelle une action sur votre contrôleur de niveau supérieur, transmettez-lui un bloc. Vous définissez le bloc pour accepter autant d'arguments que vous le souhaitez. Vous pouvez également concevoir que l'API utilise plusieurs blocs si cela vous convient mieux.

Voici deux exemples triviaux de la colle de segue. Le premier est simple montrant un paramètre passé pour l'entrée, le second pour la sortie.

// Prepare the destination view controller by passing it the input we want it to work on
// and the results we will look at when the user has navigated back to this controller's view.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results
     // by virtue of both controllers having a pointer to the same object.
     andResults:self.resultsFromNextController];
}

Ce deuxième exemple montre comment passer un bloc de rappel pour le deuxième argument. J'aime utiliser des blocs car cela permet de rapprocher les détails pertinents dans la source - la source de niveau supérieur.

// Prepare the destination view controller by passing it the input we want it to work on
// and the callback when it has done its work.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results.
     resultsBlock:^(id results) {
         // This callback could be as involved as you like.
         // It can use Grand Central Dispatch to have work done on another thread for example.
        [self setResultsFromNextController:results];
    }];
}
36
WeakPointer

Si vous souhaitez transmettre des données d’un contrôleur à un autre, essayez ce code.

FirstViewController.h

@property (nonatomic, retain) NSString *str;

SecondViewController.h

@property (nonatomic, retain) NSString *str1;

FirstViewController.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }
27
user2998756

Je cherchais cette solution depuis longtemps, Atlast je l’ai trouvée. Tout d’abord, déclarez tous les objets de votre fichier SecondViewController.h comme

@interface SecondViewController: UIviewController 
{
    NSMutableArray *myAray;
    CustomObject *object;
}

Maintenant, dans votre fichier d'implémentation, allouez la mémoire pour ces objets comme ceci

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
     if (self) 
     {
         // Custom initialization
         myAray=[[NSMutableArray alloc] init];
         object=[[CustomObject alloc] init];
     }
     return self;
}

Vous avez maintenant alloué la mémoire à Array et à l'objet. maintenant vous pouvez remplir cette mémoire avant de pousser cette ViewController

Accédez à votre SecondViewController.h et écrivez deux méthodes.

-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;

dans le fichier d'implémentation, vous pouvez implémenter la fonction 

-(void)setMyArray:(NSArray *)_myArray
{
     [myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
     [object setCustomObject:_myObject];
}

s’attendant à ce que votre CustomObject soit associée à une fonction de définition.

maintenant, votre travail de base est terminé. allez à l'endroit où vous voulez pousser la SecondViewController et faites les choses suivantes

SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];

Faites attention aux fautes d'orthographe. 

25
AsifHabib

Ce n'est pas la façon de le faire, vous devriez utiliser des délégués, je suppose que nous avons deux contrôleurs de vue ViewController1 et ViewController2 et que cette vérification est dans le premier et lorsque son état change, vous voulez faire quelque chose dans ViewController2 Pour y parvenir de la bonne manière, vous devriez faire ce qui suit:

Ajouter un nouveau fichier à votre projet (protocole Objective-C) Fichier -> Nouveau, nommez-le maintenant ViewController1Delegate ou ce que vous voulez et écrivez-le entre les directives @interface et @end

@optional

- (void)checkStateDidChange:(BOOL)checked;

Maintenant, allez à ViewController2.h et ajoutez

#import "ViewController1Delegate.h"

puis changez sa définition en

@interface ViewController2: UIViewController<ViewController1Delegate>

Maintenant, allez à ViewController2.m et à l'intérieur de l'implémentation, ajoutez:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

Maintenant, allez à ViewController1.h et ajoutez la propriété suivante:

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

Maintenant, si vous créez ViewController1 dans ViewController2 après un événement, vous devriez le faire de cette façon en utilisant des fichiers NIB:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

Vous êtes maintenant prêt, chaque fois que vous détectez l'événement de vérification modifié dans ViewController1, il vous suffit de procéder comme suit:

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

S'il vous plaît dites-moi s'il y a quelque chose qui n'est pas clair si je n'ai pas bien compris votre question.

21
Boda Taljo

Si vous souhaitez envoyer des données d'un view à un autre viewController, voici une solution:

Disons que nous avons viewControllers: viewControllerA et viewControllerB

Maintenant dans viewControllerB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

Dans viewControllerB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

Dans viewControllerA.m 

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

Voici comment vous pouvez passer des données de viewControllerA à viewControllerB sans définir de délégué. ;)

19
Aniruddh Joshi

1. Créez l'instance du premier contrôleur de vue dans le second contrôleur de vue et définissez sa propriété @property (nonatomic,assign).

2. Assigne l'instance SecondviewController de ce contrôleur de vue.

2. Lorsque vous avez terminé l'opération de sélection, copiez le tableau dans le premier View Controller. Lorsque vous déchargez SecondView, FirstView conserve les données du tableau.

J'espère que cela t'aides.

18
kaar3k

Passage de données entre FirstViewController à SecondViewController comme ci-dessous

Par exemple: 

FirstViewController String valeur en tant que

StrFirstValue = @"first";

afin que nous puissions passer cette valeur en deuxième classe en utilisant l'étape ci-dessous

1> Nous devons créer un objet chaîne dans le fichier SecondViewController.h

NSString *strValue;

2> Besoin de déclarer une propriété comme ci-dessous déclaration dans le fichier .h 

@property (strong, nonatomic)  NSString *strSecondValue;

3> Besoin de synthétiser cette valeur dans le fichier FirstViewController.m sous la déclaration d'en-tête

@synthesize strValue;

et dans FirstViewController.h:

@property (strong, nonatomic)  NSString *strValue;

4> Dans FirstViewController, à partir de quelle méthode nous passons à la seconde vue, veuillez écrire ci-dessous le code correspondant à cette méthode 

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];
16
Chris Alan

Je contribue actuellement à une solution open source à ce problème via un projet appelé MCViewFactory, qui peut être trouvé ici:

https://github.com/YetiHQ/manticore-iosviewfactory

L'idée est d'imiter le paradigme de l'intention d'Android, en utilisant une fabrique globale pour gérer la vue que vous regardez et en utilisant des "intentions" pour basculer et transmettre des données entre des vues. Toute la documentation est sur la page github, mais voici quelques faits saillants:

Vous configurez toutes vos vues dans des fichiers .XIB et les enregistrez dans le délégué de l'application tout en initialisant la fabrique.

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

// the following two lines are optional. 
[factory registerView:@"YourSectionViewController"]; 

Désormais, dans votre VC, chaque fois que vous souhaitez passer à un nouveau VC et transmettre des données, vous créez une nouvelle intention et ajoutez des données à son dictionnaire (savedInstanceState). Ensuite, il suffit de définir l’intention actuelle de l’usine:

MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];

Toutes vos vues conformes à cette configuration doivent être des sous-classes de MCViewController, qui vous permettent de remplacer la nouvelle méthode onResume:, vous permettant d'accéder aux données que vous avez transmises.

-(void)onResume:(MCIntent *)intent {
    NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
    NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];

    // ...

    // ensure the following line is called, especially for MCSectionViewController
    [super onResume:intent];
}

J'espère que certains d'entre vous trouveront cette solution utile/intéressante. 

16
user2563044

Dans mon cas, j'ai utilisé une classe singleton qui peut fonctionner comme un objet global permettant d'accéder aux données de presque partout dans l'application. La première chose à faire est de construire une classe singleton. Veuillez vous reporter à la page " À quoi doit ressembler mon singleton Objective-C? " Et ce que j'ai fait pour rendre l’objet accessible globalement, c’est simplement importé dans appName_Prefix.pch, ce qui permet d’appliquer une instruction import dans chaque classe. . Pour accéder à cet objet et l'utiliser, j'ai simplement implémenté la méthode de classe pour renvoyer l'instance partagée, qui contient ses propres variables

15
petershine

Créez la propriété sur le prochain view controller .h et définissez le getter et le setter.

Ajouter cette property dans NextVC.h sur nextVC

@property (strong, nonatomic) NSString *indexNumber;

Ajouter 

@synthesize indexNumber; dans NextVC.m

Enfin

NextVC *vc=[[NextVC alloc]init];

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];
13
Vivek Yadav

Je sais qu’il s’agit d’un sujet ardu, mais pour ceux qui cherchent à répondre à cette question avec une inclinaison de Swift et veulent un exemple simple, voici ma méthode idéale pour transmettre des données si vous utilisez une transition pour vous déplacer.

C'est semblable à ce qui précède, mais sans les boutons, les étiquettes et autres. Il suffit simplement de passer des données d’une vue à l’autre.

Installer le scénarimage

Il y a trois parties. 

  1. L'expéditeur
  2. La segue
  3. Le récepteur

Ceci est une disposition de vue très simple avec une séparation entre eux.


 Very simple view layout. Note : No navigation controller


Voici la configuration pour l'expéditeur


 The Sender


Voici la configuration pour le récepteur.


 The Receiver


Enfin, la configuration pour le segue.


 The Segue Identifier


Les contrôleurs de vue

Nous gardons cela simple, donc pas de boutons ni d'actions, nous déplaçons simplement les données de l'expéditeur au destinataire lors du chargement de l'application, puis émettons la valeur transmise vers la console.

Cette page prend la valeur initialement chargée et la transmet.

//
//  ViewControllerSender.Swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"


    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

Cette page envoie simplement la valeur de la variable à la console lors de son chargement. À ce stade, notre film préféré devrait être dans cette variable.

//
//  ViewControllerReceiver.Swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()


        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }



}

C’est ainsi que vous pourrez vous attaquer si vous souhaitez utiliser une séquence et que vos pages ne sont pas sous un contrôleur de navigation.

Une fois qu'il est exécuté, il doit basculer automatiquement vers la vue du destinataire et transmettre la valeur de l'expéditeur au destinataire, en affichant la valeur dans la console.

 Ghost Busters is a classic folks.

12

La délégation est la seule solution permettant d'exécuter de telles opérations lorsque vous utilisez des fichiers .xib. Cependant, toutes les réponses décrites ci-dessus s'appliquent aux fichiers storyboard pour les fichiers .xibs dont vous avez besoin pour utiliser la délégation. c'est la seule solution que vous pouvez. 

Une autre solution consiste à utiliser le modèle de classe singleton pour l'initialiser une fois et l'utiliser dans l'ensemble de votre application. 

10
user2786888

si vous souhaitez transmettre des données de ViewControlerOne à ViewController, essayez-les. 

faites-les dans ViewControlerOne.h

 @property (nonatomic, strong) NSString *str1;

faites-les dans ViewControllerTwo.h

 @property (nonatomic, strong) NSString *str2;

Synthétiser str2 dans ViewControllerTwo.m

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

faites-les dans ViewControlerOne.m

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

sur les boutons, cliquez sur événement, faites ceci ..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

faites-les dans ViewControllerTwo.m

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}
10
krushnsinh

Il existe une multitude de façons de le faire et il est important de choisir la bonne. L'une des décisions architecturales les plus importantes réside probablement dans la manière dont le code du modèle sera partagé ou utilisé dans l'application.

J'ai écrit un billet de blog à ce sujet il y a quelque temps: Sharing Model Code . Voici un bref résumé:

Données partagées

Une approche consiste à partager des pointeurs sur les objets du modèle entre les contrôleurs de vue. 

  • Itération de force brute sur les contrôleurs de vue (dans le contrôleur de navigation ou de barre d'onglets) pour définir les données
  • Définir les données dans prepareForSegue (si les storyboards) ou init (si programmatique)

Puisque préparer pour segue est le plus commun, voici un exemple:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

Accès indépendant

Une autre approche consiste à gérer un écran plein de données à la fois et au lieu de coupler les contrôleurs de vue les uns aux autres, coupler chaque contrôleur de vue à une source de données unique à laquelle ils peuvent accéder indépendamment. 

La manière la plus courante que j'ai vue faire cela est un singleton instance. Ainsi, si votre objet singleton était DataAccess, vous pouvez procéder comme suit dans la méthode viewDidLoad de UIViewController:

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

Il existe des outils supplémentaires qui aident également à transmettre des données:

  • Observation des valeurs clés
  • NSNotification
  • Données de base
  • NSFetchedResultsController
  • La source de données

Données de base

La bonne chose à propos de Core Data est qu’il existe des relations inverses. Donc, si vous voulez simplement donner un objet Notes à un objet NotesViewController, il aura une relation inverse avec quelque chose d'autre, tel que le bloc-notes. Si vous avez besoin de données sur le bloc-notes dans NotesViewController, vous pouvez remonter le graphe d'objets en procédant comme suit:

let notebookName = note.notebook.name

Plus d'informations à ce sujet dans mon article de blog: Sharing Model Code

10
Korey Hinton

NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewController.m

@synthesize newsHeadlineStr;
10
Mohsin Sabasara

Vous pouvez enregistrer des données dans le délégué d'application pour y accéder via les contrôleurs de vue de votre application. Tout ce que vous avez à faire est de créer une instance partagée de délégué d'application

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

Par exemple

si vous déclarez un NSArray object *arrayXYZ, vous pourrez y accéder dans n’importe quel contrôleur de vue par appDelegate.arrayXYZ

10
ak_tyagi

J'aime l'idée des objets Modèle et des objets Mock basés sur NSProxy pour valider ou supprimer des données si ce que l'utilisateur sélectionne peut être annulé. 

Il est facile de transmettre des données puisqu'il s'agit d'un seul objet ou de plusieurs objets. Si vous avez le contrôleur UINavigationController, vous pouvez conserver la référence au modèle à l'intérieur et tous les contrôleurs de vue par poussée peuvent y accéder directement à partir du contrôleur de navigation.

8
highmaintenance

Si vous souhaitez envoyer des données d'un view à un autre viewController, voici une solution:

Disons que nous avons viewControllers: ViewController et NewViewController.

dans ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

dans ViewController.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

Dans NewViewController.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

Dans NewViewController.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

Donc, de cette façon, nous pouvons passer les données d'un contrôleur de vue à un autre contrôleur de vue ...

8
Sabs

J'ai vu beaucoup de gens compliquer la situation en utilisant la méthode didSelectRowAtPath. J'utilise Core Data dans mon exemple.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

4 lignes de code à l'intérieur de la méthode et vous avez terminé. 

7
App Dev Guy

Il existe de nombreuses réponses à ces questions offrant de nombreuses façons différentes de réaliser une communication de contrôleur de vue qui fonctionnerait, mais je ne vois nulle part où il est indiqué de choisir lequel est le mieux à utiliser et lequel éviter.

En pratique, à mon avis, seules quelques solutions sont recommandées:

  • Pour transmettre des données:
    • remplacer la méthode prepare(for:sender:) de UIViewController lors de l'utilisation d'un storyboard et de segues
    • transmettre des données via un initialiseur ou des propriétés lors de transitions de contrôleur de vue via le code
  • Pour passer des données en arrière
    • mettre à jour l'état partagé de l'application (que vous pouvez transmettre entre les contrôleurs de vue à l'aide de l'une des méthodes ci-dessus)
    • utiliser la délégation
    • utiliser une séquence de détente

Solutions que je recommande de ne pas utiliser:

  • Référencer directement le contrôleur précédent au lieu d'utiliser la délégation
  • Partage de données via un singleton
  • Transmission de données via le délégué de l'application
  • Partage de données via les paramètres utilisateur par défaut
  • Passing data through notifications

Ces solutions, bien que fonctionnant à court terme, introduisent trop de dépendances qui brouilleraient l'architecture de l'application et créeraient plus de problèmes plus tard.

Pour les personnes intéressées, j’ai écrit quelques articles qui abordent ces points plus en profondeur et soulignent les divers inconvénients:

5
Matteo Manferdini

Il existe 3 types pour passer des données d'un ViewController à un autre ViewController.

  1. Par programmation
  2. Segue
  3. UserDefaults

Projet de démonstration Lien ici - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

Par programme enter image description here

Segue enter image description here

UserDefaults enter image description here

Projet de démonstration Lien ici - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

4
Kamani Jasmin

Swift 5

Bien La réponse de Matt Price convient parfaitement pour transmettre des données, mais je vais le récrire dans la dernière version de Swift, car je suis convaincu que les nouveaux programmeurs trouvent cela difficile, en raison de la nouvelle syntaxe et des nouvelles méthodes/cadres, car l'article d'origine est dans Objective -C.

Il existe plusieurs options pour la transmission de données entre les contrôleurs de vue.

  1. Utilisation du contrôleur de navigation Push
  2. Utiliser Segue
  3. Utilisation de delegate
  4. Utilisation de Notification Observer
  5. Utiliser un bloc

Je vais réécrire sa logique dans Swift avec le dernier framework iOS


Transmission de données par le biais du contrôleur de navigation Push : de ViewControllerA à ViewControllerB

Étape 1. Déclarer une variable dans ViewControllerB

var isSomethingEnabled = false

Étape 2. Variable d'impression dans la méthode ViewDidLoad de ViewControllerB '

override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue, navigation Push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }

Étape 3. Dans ViewControllerA Transmettez les données en poussant à travers le contrôleur de navigation.

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
        viewControllerB.isSomethingEnabled = true
        if let navigator = navigationController {
            navigator.pushViewController(viewControllerB, animated: true)
        }
    }

Donc, voici le code complet pour:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

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

    //MARK:Passing Data through Navigation PushViewController
    @IBAction func goToViewControllerB(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.isSomethingEnabled = true
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:  - Variable for Passing Data through Navigation Push   
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through navigation Push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Transmission de données via Segue : De ViewControllerA à ViewControllerB

Étape 1. Créez une séquence de ViewControllerA à ViewControllerB et donnez Identifier = showDetailSegue dans le scénarimage, comme indiqué ci-dessous.

 enter image description here 

Étape 2. Dans ViewControllerB Déclarez un nom viable isSomethingEnabled et affichez sa valeur.

Étape 3. Dans ViewControllerA, transmettez la valeur de isSomethingEnabled à Passage.

Donc, voici le code complet pour:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

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

    //MARK:  - - Passing Data through Segue  - - 
    @IBAction func goToViewControllerBUsingSegue(_ sender: Any) {
        performSegue(withIdentifier: "showDetailSegue", sender: nil)
    }

    //Segue Delegate Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true//passing data
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Transmission de données via délégué : De ViewControllerB à ViewControllerA

Étape 1. Déclarer le protocoleViewControllerBDelegate _ dans le fichier ViewControllerB mais en dehors de la classe.

protocol ViewControllerBDelegate: NSObjectProtocol {

    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

Étape 2. Déclarer une instance de variable déléguée dans ViewControllerB

var delegate: ViewControllerBDelegate?

Étape 3. Envoyer des données pour le délégué dans la méthode viewDidLoad de ViewControllerB

delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")

Étape 4. Confirmez ViewControllerBDelegate dans ViewControllerA

class ViewControllerA: UIViewController, ViewControllerBDelegate  {
// to do
}

Étape 5. Confirmez que vous implémenterez un délégué dans ViewControllerA

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self//confirming delegate
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }

Étape 6. Implémenter une méthode déléguée pour la réception de données dans ViewControllerA

func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

Donc, voici le code complet pour:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController, ViewControllerBDelegate  {

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

    //Delegate method
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

    @IBAction func goToViewControllerForDelegate(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

//Protocol decleare
protocol ViewControllerBDelegate: NSObjectProtocol {
    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

class ViewControllerB: UIViewController {
    var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        //MARK:  - - - -  Set Data for Passing Data through Delegate  - - - - - -
        delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")
    }
}

Transmission de données via Notification Observer : De ViewControllerB à ViewControllerA

Étape 1. Définir et publier des données dans Notification Observer dans ViewControllerB

let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)

Étape 2. Ajouter Notification Observer dans ViewControllerA

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Étape 3. Réception de la valeur des données de notification dans ViewControllerA

@objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }

Donc, voici le code complet pour:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: Method for receiving Data through Post Notification 
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Post Notification
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }
}

Transmission de données par bloc : de ViewControllerB à ViewControllerA

Étape 1. Déclarer un bloc dans ViewControllerB

var autorisationCompletionBlock: ((Bool) -> ())? = {_ in}

Étape 2. Définir les données en bloc dans ViewControllerB

if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }

Étape 3. Recevez des données de bloc dans ViewControllerA

//Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }

Donc, voici le code complet pour:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

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

    //MARK:Method for receiving Data through Block
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "showDetailSegue") {
                let controller = segue.destination as? ViewControllerB
                controller?.isSomethingEnabled = true

                //Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }
            }
        }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:Variable for Passing Data through Block
    var authorizationCompletionBlock:((Bool)->())? = {_ in}

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Block
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }
    }
}

Vous pouvez trouver un exemple complet d’application sur mon GitHub Faites-le-moi savoir si vous avez des questions à ce sujet.

3
swiftBoy

Ceci est un très bon tutoriel pour quiconque en veut un. Voici l'exemple de code:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myIdentifer]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        myViewController *destViewController = segue.destinationViewController;
        destViewController.name = [object objectAtIndex:indexPath.row];
    }
}
3
crazy_tiger_corp

UTILISATION DU CENTRE DE NOTIFICATION

Pour Swift 3

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }

Pour Swift 4

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 @objc func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }
3
Sachin Rasane

pour envoyer les données d'un VC à un autre, utilisez cette approche simple:

YourNextVC *nxtScr = (YourNextVC*)[self.storyboard  instantiateViewControllerWithIdentifier:@"YourNextVC"];//Set this identifier from your storyboard

nxtScr.comingFrom = @"PreviousScreen"l
[self.navigationController nxtScr animated:YES];
2
Dalvik

eh bien, nous avons peu de façons de travailler avec le système de délégués ou en utilisant storyboardSegue 

1- As working with setter and getter method like in viewController.h
   @property (retain, nonatomic) NSString *str;
   now, in viewController.m
   @synthesize str;


   here i have pdf url and segue to another viewController like this and pdfObject is my pdfModel basicilly is NSOBJECT class.  

   str =[NSString stringWithFormat:@"%@",pdfObject.objPath];
NSLog(@"pdfUrl :***: %@ :***:",pdfUrl);

[self performSegueWithIdentifier:@"programPDFViewController_segue" sender:self];

marque pragma - Navigation

  // In a storyboard-based application, you will often want to do a little preparation before navigation

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if ([[segue identifier] isEqualToString:@"programPDFViewController_segue"]){
    programPDFViewController *pdfVC = [segue destinationViewController];
    [pdfVC setRecievedPdfUrl:str];

   }
 }

Maintenant, avec succès, j'ai reçu ma chaîne d'URL pdf et d'autres ViewController et je l'utilise dans WebView ... 

2- En travaillant avec des délégués comme celui-ci, j'ai une classe d'utilitaires NSObject contenant mes méthodes de dateFormatter, sharedInstance, EscapeWhiteSpaceCharacters, convertImageToGrayScale et d'autres méthodes avec lesquelles j'ai travaillé tout au long de l'application, maintenant dans utilities.h

dans ce cas, vous n'avez pas besoin de créer des variables à tout moment, en analysant les données d'un contrôleur de vue à un autre, une fois la variable chaîne créée dans utilities.h et utilisé à nouveau

  @interface Utilities : NSObject

  Utilities.h
 +(Utilities*)sharedInstance;

 @property(nonatomic,retain)NSString* strUrl;

maintenant dans utilities.m

   @implementation utilities


  +(utilities*)sharedInstance
  {
  static utilities* sharedObj = nil;
  if (sharedObj == nil) {
    sharedObj = [[utilities alloc] init];
    }
   return sharedObj;
  }

now its done come to your firstViewController.m and call delegate

NSString*str =[NSString stringWithFormat:@"%@",pdfObject.objPath];

[Connection sharedInstance].strUrl=nil;
[Connection sharedInstance].strUrl=str;

 Now go to you secondViewController.m directly use it without creating variable 

 in viewwillapear what i did

 -(void)viewWillAppear:(BOOL)animated{
     [super viewWillAppear:YES];

   [self webViewMethod:[Connection sharedInstance].strUrl];

 }


 -(void)WebViewMethod:(NSString)Url{

 // working with webview enjoy coding :D

 }

ce travail de délégué est fiable avec la gestion de la mémoire 

2
Nayab Khan

Je recommande les blocs/fermetures et les constructeurs personnalisés.

Supposons que vous deviez passer une chaîne de FirstViewController à SecondViewController.

Votre premier contrôleur de vue. 

class FirstViewController : UIViewController {

    func moveToViewControllerB() {

        let second_screen = SecondViewController.screen(string: "DATA TO PASS", call_back: {
            [weak self] (updated_data) in
            ///This closure will be called by second view controller when it updates something
        })
        self.navigationController?.pushViewController(second_screen, animated: true)
    }


}

Votre deuxième contrôleur de vue

class SecondViewController : UIViewController {

    var incoming_string : String?
    var call_back : ((String) -> Void)?

    class func screen(string: String?, call_back : ((String) -> Void)?) -> SecondViewController {

        let me = SecondViewController(nibName: String(describing: self), bundle: Bundle.main);
        me.incoming_string = string
        me.call_back = call_back
        return me
    }

    // Suppose its called when you have to update FirstViewController with new data.
    func updatedSomething() {

        //Executing block that is implemented/assigned by the FirstViewController.
        self.call_back?("UPDATED DATA")
    }

}
1
Umair

Vous pouvez créer Push segue du contrôleur de vue source au contrôleur de vue de destination et attribuer un nom d’identifiant comme ci-dessous .  enter image description here

Vous devez exécuter la scène de didselectRowAt comme ceci.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    performSegue(withIdentifier: "segue", sender: self)
}

Et vous pouvez passer le tableau des éléments sélectionnés à partir de la fonction ci-dessous.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    print(indexNumber!)
    let VC = segue.destination as! AddTransactionVC
   VC.val = CategoryData[indexNumber!] . //You can pass here entire array instead of array element.

}

Et vous devez vérifier la valeur dans viewdidload de viewcontroller de destination, puis la stocker dans la base de données.

override func viewDidLoad{
 if val != ""{
        btnSelectCategory.setTitle(val, for: .normal)
    }
}
1
Parth Barot

Je préfère le faire sans délégués et segues. Cela peut être fait avec un init personnalisé ou en définissant des valeurs optionnelles.

1. Custom init

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB(string: "Blabla", completionClosure: { success in
      print(success)
    })
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  private let completionClosure: ((Bool) -> Void)
  init(string: String, completionClosure: ((Bool) -> Void)) {
    self.completionClosure = completionClosure
    super.init(nibName: nil, bundle: nil)
    title = string
  }

  func finishWork() {
    completionClosure()
  }
}

2. Facultatif vars

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB()
    viewController.string = "Blabla"
    viewController.completionClosure = { success in
      print(success)
    }
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  var string: String? {
    didSet {
      title = string
    }
  }
  var completionClosure: ((Bool) -> Void)?

  func finishWork() {
    completionClosure?()
  }
}
1
Timur Bernikovich

Une façon de faire cela en Apple consiste à utiliser Segues . Vous devez utiliser la fonction prepareForSegue ()

Il existe de nombreux didacticiels de qualité, dont un: https://www.iphonelife.com/content/unleash-your-inner-app-developer-part-21-passing-data-between-controllers

Lisez également les documents Apple sur l’utilisation de segments: https://developer.Apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html

1
tmac_balla

Vous devez toujours suivre le concept MVC lors de la création d'applications pour iOS . Il existe deux scénarios dans lesquels vous pouvez souhaiter transmettre des données d'un ViewController à un autre:

  1. Quand il y a un "A" ViewContoller dans la hiérarchie et que vous voulez envoyer des données à "B" qui est le next viewcontroller. Dans ce cas, vous devez utiliser Segue. Il suffit de définir un identifiant pour la séquence, puis dans le VC "A", écrivez le code suivant:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "A to B segue identifier" {
            let bViewController = segue.destination as! UIDocumentBrowserViewController
            bViewController.data = someData
        }
    }
    
  2. Quand il y a une A qui a ouvert B sur lui-même en tant que modal (ou intégré). Maintenant, le contrôleur de vue B devrait être aveugle à propos de son parent. Donc, le meilleur moyen de renvoyer des données à A est d'utiliser Delegation. Créez un protocole de délégué dans le contrôleur de vue B et une propriété delegate. Donc, B rapportera (renverra les données) à son délégué. Dans le contrôleur de vue A, nous implémentons le protocole de délégué B viewcontroller et nous allons définir self comme propriété delegate de B viewcontroller dans la méthode prepare(forSegue:).

Voici comment cela devrait être implémenté correctement. J'espère que ça aide

0
Shahin