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


Je suis nouveau sur iOS et Objective-C et tout le paradigme 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 sur une autre vue avec un UITableViewController et j'ai activé plusieurs sélections.

Ma question est, comment puis-je transférer les données d'une vue à l'autre? Je vais tenir les sélections sur le UITableView dans un tableau, mais comment puis-je le renvoyer à la vue précédente du formulaire d'entrée de données afin qu'il puisse être sauvegardé avec les autres données dans les données de base à la soumission du formulaire?

J'ai surfé autour et j'ai vu certaines personnes déclarer un tableau dans le délégué de l'application. J'ai lu quelque chose à propos de 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 faire cela et comment j'y arriverais?


1205
2018-03-06 12:43


origine


Réponses:


Cette question semble être très populaire ici sur stackoverflow alors j'ai pensé que j'essaierais de donner une meilleure réponse pour aider les gens qui commencent 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é.

Transmission de données en aval

Transmettre des données à un contrôleur de vue à partir d'un autre contrôleur de vue. Vous utiliseriez cette méthode si vous vouliez passer un objet / valeur d'un contrôleur de vue à un autre contrôleur de vue sur lequel vous pourriez pousser une pile de navigation.

Pour cet exemple, nous aurons ViewControllerA et ViewControllerB

Pour passer un BOOL valeur de ViewControllerA à ViewControllerB nous ferions ce qui suit.

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

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

    #import "ViewControllerB.h"
    

    Ensuite, où vous voulez charger la vue, par exemple. didSelectRowAtIndex ou une IBAction vous devez définir la propriété dans ViewControllerB avant de le pousser sur la pile de nav.

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

    Cela va définir isSomethingEnabled dans ViewControllerB à BOOL valeur YES.

Passage de données en utilisant Segues

Si vous utilisez des Storyboards, vous utilisez très probablement des segues et aurez besoin de cette procédure pour transmettre des 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 un BOOL de ViewControllerA à ViewControllerB nous ferions ce qui suit:

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

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

    #import "ViewControllerB.h"
    
  3. Créer un segue à partir de ViewControllerA à ViewControllerB sur le storyboard et lui donner un identifiant, dans cet exemple, nous l'appellerons "showDetailSegue"

  4. Ensuite, nous devons ajouter la méthode à ViewControllerA cela est appelé quand n'importe quel segue est exécuté, à cause de cela, nous devons détecter quel segue a été appelé et ensuite faire quelque chose. Dans notre exemple, nous allons vérifier pour "showDetailSegue" et si cela est effectué, nous allons passer notre BOOL valeur à ViewControllerB

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

    Si vous avez vos vues intégrées dans un contrôleur de navigation, vous devez modifier légèrement la méthode ci-dessus

    -(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;
        }
    }
    

    Cela va définir isSomethingEnabled dans ViewControllerB à BOOL valeur YES.

Passage des données

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

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

Pour ViewControllerA être délégué de ViewControllerB il doit se conformer à ViewControllerBle protocole que nous devons spécifier. Cela dit ViewControllerA quelles méthodes il doit implémenter.

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

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

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. Dans ViewControllerB nous appelons un message sur le delegate quand on fait apparaître 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 en ViewControllerA.h, dire ViewControllerA importer ViewControllerB et se conformer à son protocole.

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

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

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

Les références


1557
2018-03-16 11:39



Rapide

Il y a des tonnes et des tonnes d'explications ici et autour de StackOverflow, mais si vous êtes un débutant essayant juste de faire quelque chose de basique, essayez de regarder ce tutoriel sur YouTube (c'est ce qui m'a aidé à comprendre).

Passage des données au prochain View Controller

Ce qui suit est un exemple basé sur la vidéo. L'idée est de passer une chaîne du champ de texte du First View Controller à l'étiquette du second View View.

enter image description here

Créez la disposition du storyboard dans l'interface Builder. Pour faire la segue, tu viens de Contrôle cliquez sur le bouton et faites glisser sur le second View View Controller.

Premier contrôleur de vue

Le code du First View Controller 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!
    }

}

Deuxième contrôleur de vue

Et le code pour le second View View 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
    }

}

Ne pas oublier

  • Accrocher les points de vente pour le UITextField et le UILabel.
  • Définissez les premier et deuxième contrôleurs de vue sur les fichiers Swift appropriés dans IB.

Renvoyer les données au contrôleur de vue précédent

Pour renvoyer des données du deuxième contrôleur de vue au premier contrôleur de vue, vous utilisez un protocole et un délégué. Cette vidéo est une marche très claire cependant de ce processus:

Ce qui suit est un exemple basé sur la vidéo (avec quelques modifications).

enter image description here

Créez la disposition du storyboard dans l'interface Builder. Encore une fois, pour faire la segue, vous venez de Contrôle faites glisser le bouton vers le second contrôleur de vue. Définir l'identifiant du segue sur showSecondViewController. Aussi, n'oubliez pas de brancher les prises et les actions en utilisant les noms dans le code suivant.

Premier contrôleur de vue

Le code du First View Controller 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 coutume DataEnteredDelegate protocole.

Deuxième contrôleur de vue et protocole

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 le protocol est en dehors de la classe View Controller.

C'est tout. En cours d'exécution de l'application, vous devriez être en mesure de renvoyer les données du second contrôleur de vue au premier.


131
2017-08-11 06:35



Le M dans MVC est pour "Modèle" et dans le paradigme MVC le rôle des classes de modèles 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 rien sur les 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 d'un contrôleur est de servir de médiateur entre la vue et le 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 dans votre tableau. La vue racine de votre application affiche cette table et elle peut être chargée de charger le 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 détaillée remplit le dictionnaire et revient. Le dictionnaire fait déjà partie du modèle, donc rien d'autre ne doit arriver.


118
2018-03-06 13:49



Il existe plusieurs façons par lesquelles une donnée peut être reçue dans une classe différente dans iOS. Par exemple -

  1. Initialisation directe après l'attribution d'une autre classe.
  2. Délégation - pour renvoyer des données
  3. Notification - pour diffuser des données à plusieurs classes en une seule fois
  4. Enregistrement dans NSUserDefaults - pour y accéder plus tard
  5. Cours Singleton
  6. Bases de données et autres mécanismes de stockage comme plist, etc.

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

Nous pouvons le comprendre en utilisant deux contrôleurs - Contrôleur1 et Contrôleur2 

Supposons que dans la classe Controller1 vous voulez créer l'objet Controller2 et le pousser avec une valeur String 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, il y aura cette fonction

@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 même manière:

- (void)pushToController2 {

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

Pour passer plusieurs valeurs, vous pouvez utiliser les paramètres multiples comme:

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

Donc, 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


85
2018-04-08 10:24



Après plus de recherches, il a semblé que les Protocoles et les Délégués étaient la bonne façon de faire cela.

J'ai fini par utiliser cet exemple

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

Travaillé bien 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


74
2018-03-13 21:20



Je trouve la version la plus simple et la plus élégante avec des blocs qui passent. Nommez le contrôleur de vue qui attend les données renvoyées comme "A" et renvoyez le contrôleur de vue comme "B". Dans cet exemple, nous voulons obtenir 2 valeurs: d'abord Type1 et seconde de Type2.

En supposant que nous utilisions Storyboard, le premier contrôleur règle le bloc de rappel, par exemple pendant la préparation du segue:

- (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);

Que dans le fichier d'implémentation BViewController.m après que nous ayons les valeurs désirées pour retourner notre callback devrait être appelé:

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

Une chose à retenir est que l'utilisation de bloc doit souvent gérer des références fortes et faibles comme expliqué ici


59
2017-10-14 18:11



Il y a de bonnes informations dans la plupart des réponses données, mais aucune n'aborde complètement la question.

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

L'affiche originale a également demandé à propos de Singletons et l'utilisation de AppDelegate. Ces questions doivent être répondues.

Pour aider quelqu'un d'autre à regarder cette question, qui veut une réponse complète, je vais essayer de la fournir.

Scénarios d'application

Plutôt que d'avoir une discussion très hypothétique et abstraite, cela aide à avoir des applications concrètes à l'esprit. 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 un: Deux contrôleurs de vue maximum ont besoin de partager des informations. Voir le diagramme un.

diagram of original problem

Il y a deux contrôleurs de vue dans l'application. Il y a un ViewControllerA (formulaire de saisie de données) et 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 de données. 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 la même information. Voir le diagramme deux.

home inventory application diagram

Il y a quatre contrôleurs de vue dans l'application. Il s'agit d'une application basée sur des onglets pour la gestion de l'inventaire de la maison. Trois contrôleurs de vue 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 de la maison
  • ViewControllerD - Ajouter un nouveau formulaire d'article

Chaque fois qu'un élément individuel est créé ou modifié, il doit également se synchroniser avec les autres contrôleurs de vue. Par exemple, si nous ajoutons un bateau dans ViewControllerD, mais qu'il n'est pas encore assuré, alors le bateau doit apparaître quand l'utilisateur va à ViewControllerA (Luxury Items), et aussi ViewControllerC (Entire Home Inventory), mais pas quand l'utilisateur va à ViewControllerB (Articles non assurés). Nous devons non seulement ajouter de nouveaux éléments, mais aussi supprimer des éléments (qui peuvent être autorisés à partir de l'un des quatre contrôleurs de vue) ou modifier des éléments existants (qui peuvent être autorisés à partir du "Ajouter un nouveau formulaire"). 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 et il doit donc y avoir une sorte de communication avec tous les autres contrôleurs de vue lorsqu'un contrôleur de vue unique modifie les données sous-jacentes. Il devrait être assez évident que nous ne voulons pas que chaque contrôleur de vue communique directement avec chaque autre contrôleur de vue dans ce scénario. Dans le cas où ce n'est pas évident, considérons si nous avions 20 contrôleurs de vue différents (plutôt que seulement 4). Dans quelle mesure est-il difficile et sujette à erreur d'aviser chacun des 19 autres contrôleurs de vue chaque fois qu'un contrôleur de vues effectue un changement?

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

Dans le scénario un, nous avons plusieurs solutions viables, comme d'autres réponses ont donné

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

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

  • Modèle d'observateur
  • Singletons

UNE singleton est une instance d'une classe, cette instance étant la seule instance existant au cours de sa vie. Un singleton tire son nom du fait qu'il s'agit de l'instance unique. Normalement, les développeurs qui utilisent des singletons ont des 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 comment un singleton s'intègre dans le modèle d'observateur. Le modèle d'observateur est utilisé pour qu'un objet réponde aux changements d'un autre objet. Dans le second scénario, nous avons quatre contrôleurs de vue différents, qui veulent tous savoir à propos des changements apportés aux données sous-jacentes. Les "données sous-jacentes" devraient appartenir à une instance unique, un singleton. Le "savoir sur les changements" est accompli en observant les changements apportés au singleton.

L'application d'inventaire de maison aurait une instance unique d'une classe qui est 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

Lorsque la collection d'éléments de l'inventaire de la maison change, les contrôleurs de vue doivent être mis au courant de cette modification. La définition de classe ci-dessus ne rend pas évident comment cela va se passer. Nous devons suivre le modèle d'observateur. Les contrôleurs de vue doivent observer formellement le sharedManager. Il y a deux façons d'observer un autre objet:

  • Key-Value-Observation (KVO)
  • NSNotificationCenter.

Dans le scénario deux, nous n'avons pas une seule propriété du HouseholdInventoryManager qui pourrait être observée en utilisant KVO. Parce que nous n'avons pas une seule propriété qui est facilement observable, le modèle d'observateur, dans ce cas, doit être implémenté en utilisant NSNotificationCenter. Chacun des quatre contrôleurs de vue s'abonnait à des notifications et le gestionnaire partagé envoyait des notifications au centre de notification, le cas échéant. Le gestionnaire d'inventaire n'a pas besoin de savoir quoi que ce soit à propos des contrôleurs de vue ou des instances d'autres classes qui pourraient être intéressées à savoir quand la collection d'éléments d'inventaire change; NSNotificationCenter prend en charge ces détails d'implémentation. Les contrôleurs de vue s'abonnent simplement aux notifications, et le gestionnaire de données publie simplement des notifications.

Beaucoup de programmeurs débutants profitent du fait qu'il y en a toujours exactement un Délégué à l'application dans la durée de vie de l'application, globalement accessible. Les programmeurs débutants utilisent ce fait pour placer des objets et des fonctionnalités dans l'appDelegate pour faciliter l'accès depuis n'importe quel endroit de l'application. Le fait que AppDelegate soit un singleton ne signifie pas qu'il doit remplacer tous les autres singletons. Ceci est une mauvaise pratique car elle place trop de charge sur une classe, brisant de bonnes pratiques orientées objet. Chaque classe devrait avoir un rôle clair qui est facilement expliqué, souvent juste par le nom de la classe.

Chaque fois que votre délégué aux applications commence à être gonflé, commencez à supprimer la fonctionnalité en 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.

Les références


46
2018-04-05 22:04



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é à cette touche dans le contrôleur de vue suivant.

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

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


37
2017-09-27 10:38



Transférer des données de ViewController 2 (destination) à viewController 1 (Source) est la chose la plus intéressante. En supposant que vous utilisez storyboard, ce sont toutes les façons que j'ai découvertes:

  • Déléguer
  • Notification
  • Valeurs par défaut de l'utilisateur
  • Singleton

Ceux-ci ont déjà été discutés ici.

J'ai trouvé il y a plus de façons:

-En utilisant les rappels de bloc:

l'utiliser dans le prepareForSegue méthode dans le VC1

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

-Utiliser les storyboards Dérouler (Quitter)

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

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

Dans le storyBoard accrocher le bouton "retour" à la sortie verte bouton (se détendre) de la vc.  Maintenant vous avez une section qui "remonte" donc vous pouvez utiliser le Propriété destinationViewController dans le prepareForSegue de VC2 et changer toute propriété de VC1 avant qu'il ne retourne.

  • Une autre option d'utilisation des storyboards Undwind (Exit) - vous pouvez utilisez 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 changer n'importe quelle propriété que vous voulez partager.

Dans les deux options de déroulement, vous pouvez définir la propriété de l'étiquette du bouton et la vérifier         the prepareForSegue.

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

:) À votre santé.


37
2018-04-11 00:33



L'OP ne mentionne pas les contrôleurs de vue, mais beaucoup de réponses le font, que je voulais intégrer à ce que certaines des nouvelles fonctionnalités du LLVM permettent de rendre plus facile quand on veut passer des données d'un contrôleur de vue à un autre, puis obtenir des résultats.

Segues Storyboard, les blocs ARC et LLVM rendent cela plus facile que jamais pour moi. Certaines réponses mentionnaient déjà les storyboards et les segues, mais comptaient encore sur la délégation. Définir des délégués fonctionne certainement mais certaines personnes peuvent trouver plus facile de passer des pointeurs ou des blocs de code.

Avec UINavigators et segues, il existe des moyens faciles de transmettre des informations au contrôleur subordonné et de récupérer les informations. ARC rend simple le passage de pointeurs vers des objets dérivés de NSObjects, donc si vous voulez que le contrôleur subservient ajoute / modifie / modifie certaines données pour vous, passez-le à une instance mutable. Les blocs facilitent les actions de passage, donc si vous voulez que le contrôleur subordonné appelle une action sur votre contrôleur de niveau supérieur, passez-lui un bloc. Vous définissez le bloc pour accepter n'importe quel nombre d'arguments qui a du sens pour vous. Vous pouvez également concevoir l'API pour utiliser plusieurs blocs si cela 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 passer un bloc de rappel pour le second argument. J'aime utiliser des blocs parce que les détails pertinents sont rapprochés 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];
    }];
}

35
2018-02-21 22:26



Si vous voulez 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];
 }

26
2017-11-18 12:48