web-dev-qa-db-fra.com

Transmission de données entre les contrôleurs de vue à l'aide de Segue

Je suis nouveau sur iOS. Je suis confronté à un problème de transmission des données entre ViewControllers. J'ai trois viewControllers (view_1, view_2 et view_3).

Voici ma configuration: -

  • Sélectionnez view_1
  • pousse view_2
  • pousse view_3

Je veux envoyer la référence (id) ViewController de 'view_1' à 'view_3'. donc j'inclus include "view_3" dans 'view_1' et définissez la valeur dans la variable de 'view_3' (en utilisant view_3 *v3=[[view_3 alloc] init ]; v3.reference=self;). Dans la console, il affiche:

contrôleur de vue: -; <ViewController: 0x89e9540>

dans le 'view_1' mais dans le 'view_3', dans la console il montre

contrôleur de vue (null)

Mais quand j'ai utilisé 'view_2' pour transmettre ces données, son travail. Mais comment? Je veux connaître ce comportement, et existe-t-il une solution pour créer cela?

veuillez aider.

24
MAX

La "transmission de données au contrôleur de destination" lorsqu'un déclenchement est déclenché sera obtenue en remplaçant la méthode prepareForSegue:sender:.

Généralement, vous passez data et PAS le contrôleur de vue source, au contrôleur de vue de destination. Les "données" peuvent être un certain aspect du "modèle" de votre application. C'est un objet comme "User", ou peut-être un tableau contenant "User", etc.

Le contrôleur de vue destination doit pas avoir une connaissance du contrôleur de vue source. Cela signifie que le contrôleur de vue de destination n'a pas besoin d'importer l'en-tête du contrôleur de vue source.

D'un autre côté, le source view controller may a connaissance de la classe concrète du destination view controller ou d'un base classe du contrôleur de vue de destination, et donc importera l'en-tête du contrôleur de vue de destination.

Voir: Configuration du contrôleur de destination quand une séquence est déclenchée

Si vous avez besoin d'une sorte de "protocole de communication" entre la source et la destination, vous pouvez utiliser Délégation pour communiquer avec d'autres contrôleurs de vue. Cela implique la définition d'un @protocole (par exemple avoir une méthode doneButton) et une propriété delegate qui est définie dans le contrôleur de vue de destination. Le protocole doit être défini dans l'en-tête du contrôleur de vue de destination, s'il est spécifique au contrôleur de vue de destination. Habituellement, vous définissez le protocole à partir du point de vue du contrôleur de destination et non à partir des exigences du contrôleur source.

Le contrôleur de vue source crée ensuite un délégué (sauf s'il est déjà lui-même) et définit le delegate du contrôleur de vue de destination. Le contrôleur de vue de destination enverra les méthodes déléguées au délégué, et le délégué les gérera.

Maintenant, passer des "données" d'un VC_A à VC_B devrait être simple. Vous devriez lire quelques exemples qui utilisent prepareForSegue:sender:. Par exemple, le contrôleur de vue destination peut avoir une propriété data qui représente le chose qu'il doit afficher. Le contrôleur de vue source doit définir cette propriété dans prepareForSegue:sender:.

Le passage de données de VC_A sur VC_B à VC_C devrait également être simple.

Remarque: chaque contrôleur de vue peut - adapter (séparer, modifier, préparer, découper, transformer, etc.) c'estdata pour en faire un approprié data pour le contrôleur de vue suivant.


Si VC_C a besoin de données qui ne sont pas disponibles dans son contrôleur de vue source VC_B, il existe deux approches pour résoudre ce problème. Cependant, c'est généralement un signe de mauvaise conception.

Vous pourriez avoir un modèle d'application, qui est global. Supposons que votre "modèle d'application" soit un objet de type Document. Supposons qu'à tout moment il n'y ait qu'une une instance de ce modèle d'application. Ensuite, le modèle est un "Singleton", auquel pourrait être accessible de n'importe où dans votre application comme ceci:

Document* document = [Document sharedDocument];

Cependant, la meilleure façon d'obtenir une instance d'un modèle est dans le contrôleur de vue d'abord qui nécessite l'accès à celui-ci, dans ce cas: VC_A.

VC_A transmet ensuite une instance Document au contrôleur de vue suivant VC_B. Et VC_B transmet l'objet document à VC_C.

Vous devriez lire la documentation officielle " Afficher le guide de programmation du contrôleur pour iOS ".


Exemple 1

Supposons que vous ayez une liste "Utilisateurs". La liste doit être affichée dans un contrôleur de vue de table, et il doit également y avoir une vue détaillée, montrant les détails d'un utilisateur.

Le contrôleur de vue de table aura une propriété "data" users:

Dans UsersTableViewController.h :

@interface UsersTableViewController : UIViewController
@property (nonatomic, readonly) NSArray* users;
@end

(Strictement, cette propriété user n'a pas besoin d'être publique. Par exemple, si la vue de table obtient en interne la liste des utilisateurs elle-même, il n'est pas nécessaire d'y accéder de l'extérieur.

Le tableau "utilisateurs" est le données de la vue de table qui doit être affiché en lignes. Chaque ligne affiche un "résumé" d'un utilisateur.

Plus de détails sur un utilisateur doivent être affichés dans un contrôleur de vue de détail. Les données du contrôleur de vue détaillée sont un utilisateur unique de type User.

Lorsque l'utilisateur tabule une certaine ligne dans la vue de table, le contrôleur de vue de détail s'affiche. Avant qu'il ne soit affiché, le contrôleur de vue de table doit configurer le contrôleur de vue de détail: le contrôleur de vue de table attribue à la "propriété de données" du contrôleur de vue de détail l'actuelle - utilisateur sélectionnée. Ainsi, le contrôleur de vue de détail doit avoir une propriété publicuser:

@interface UserViewController : UIViewController
@property (nonatomic) User* user;
@end

Le contrôleur de vue de table configure le contrôleur de vue de détail dans prepareForSegue:sender::

Dans UsersTableViewController.m

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"ShowUserDetails"]) {
        UserViewController* userViewController = [segue destinationViewController];
        userViewController.user = [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
    }
}

Exemple 2

Le deuxième exemple est plus complexe et utilise la "délégation" comme moyen d'établir une communication entre les contrôleurs.

Attention:

Ce n'est pas un exemple complet. Le but de cet exemple doit montrer comment utiliser la "délégation". Une implémentation complète des tâches de données, comme indiqué dans l'exemple, nécessitera beaucoup plus d'efforts. Dans ces scénarios comme ceux-ci, la "délégation" sera l'approche la plus privilégiée pour y parvenir (à mon humble avis).

Supposons que nous voulons

  • Afficher un utilisateur
  • Modifier (modifier) ​​un utilisateur
  • Créer un nouvel utilisateur et
  • Supprimer un utilisateur

depuis la vue de détail.

Ces "tâches de données" ne doivent pas être effectuées par le contrôleur de vue de détail lui-même, mais un délégué est responsable de ces tâches de données.

Ces actions de données seront traitées par le délégué:

@protocol UserDataSourceDelegateProtocol <NSObject>
- (User*) viewControllerUser:(UserViewControllerBase*)viewController;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithDeletedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithCreatedUser:(User*)user;
@end

Ce protocole reflète les méthodes CRUD de base (Créer, Lire, Mettre à jour, Supprimer).

Encore une fois, nous ne voulons pas que le contrôleur de vue de détail lui-même exécute ces méthodes de données, mais à la place, cela sera effectué par une instance implémentant le UserDataSourceDelegateProtocol. Le contrôleur de vue de détail possède une propriété de ce délégué et envoie ces "tâches de données" au délégué.

Il peut y avoir plusieurs contrôleurs de vue de détail, toutes les sous-classes de la classe abstraite UserViewControllerBase qui gèrent le show, edit et create tâches. La suppression d'un utilisateur peut être effectuée dans la vue de table et dans le contrôleur de vue "Show User":

  • ShowUserViewController
  • EditUserViewController
  • NewUserViewController

Par exemple, le EditUserViewController enverra viewController:dismissWithUpdatedUser: lorsque l'utilisateur appuie sur le bouton "retour" ET si l'utilisateur a modifié l'objet utilisateur. Désormais, le délégué peut ou non autoriser le rejet de la vue détaillée. Il peut par exemple le désactiver lorsqu'il y a des erreurs de validation.

Le protocole UserDataSourceDelegateProtocol mai doit être implémenté dans le contrôleur de vue racine, le contrôleur de vue de table par exemple. Cependant, une classe distincte dont la seule responsabilité est de gérer les tâches de données peut être plus appropriée. Dans l'exemple ci-dessous, le contrôleur de vue de table sera également ce gestionnaire de données.

UserDataSourceDelegateProtocol peut être défini dans un en-tête supplémentaire.

Dans UsersTableViewController.m :

#import "UserDataSourceDelegateProtocol.h"
#import "ShowUserViewController.h"


@interface UsersTableViewController () <UserDataSourceDelegateProtocol> 
@property (nonatomic, readonly) NSArray* users;
@end


// This delegate will be called when the detail view controller request 
// the user object which shall be displayed.
- (User*) viewControllerUser:(UserViewControllerBase*)viewController {
    return [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}

Ici, le contrôleur de vue de table configure le contrôleur de vue Afficher les détails de l'utilisateur:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:UserShowSegueID])
    {
        ShowUserViewController* showViewController = segue.destinationViewController;
        showViewController.delegate = self; // Data Source Handler is self
    }
}

Le contrôleur de vue "Edit User" est généralement un contrôleur de vue de destination du contrôleur de vue "Show User", qui est affiché lorsque l'utilisateur appuie sur le bouton "Edit".

Le contrôleur de vue "Afficher l'utilisateur" configurera le délégué pour le contrôleur de vue "Modifier l'utilisateur" obtient le même délégué:

Dans ShowUserViewController.m

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:UserEditSegueID])
    {
        EditUserViewController* editViewController = segue.destinationViewController;
        editViewController.delegate = self.delegate; // pass through the data source hanlder
    }
}

Le délégué de données peut gérer un utilisateur mis à jour comme suit:

Dans UsersTableViewController.m :

- (void) viewController:(UserViewControllerBase*)viewController
 dismissWithUpdatedUser:(User*)user {
    if (/* is valid user and can be saved */) {
        [viewController.presentingViewController dismissViewControllerAnimated:YES
                                                                     completion:nil];
    }
}
46
CouchDeveloper

Ce Swift sur YouTube m'a aidé à comprendre enfin comment faire cela.

J'ai mis en place un exemple simple dans le même sens. Écrivez du texte dans un champ de texte, appuyez sur le bouton et il place le texte dans une étiquette dans le prochain contrôleur de vue.

Configurer le storyboard

enter image description here

Ce n'est pas très difficile. Créez la disposition du storyboard dans le générateur d'interface. Pour te faire enchaîner juste control cliquez sur le bouton et faites-le glisser vers le Second View Controller.

Contrôleur First View

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 prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        // get a reference to the second view controller
        let secondViewController = segue.destinationViewController 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 du Second View Controller 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'oublie pas

  • Branchez les prises pour le UITextField et le UILabel.
  • Définissez les premier et deuxième View Controllers sur les fichiers Swift Swift dans IB.

Le processus de transmission des données à un troisième contrôleur de vue serait le même.

12
Suragch

il y a une solution mais pas la manière la plus appropriée.

ViewController3.h

-(void)getUser:(NSString *)strPassedUser;

allez dans votre ViewController3.m et au-dessus du @interface ajoutez une variable comme celle-ci

NSString *recievingVariable ;

puis certains à l'intérieur du ViewController3.m

-(void)getUser:(NSString *)strPassedUser
{
    recievingVariable = strPassedUser;
}

ViewController1 et importez ViewController3 puis faites comme ça ..

ViewController3 * vc3 = [ViewController3 alloc]getUser :@"me"];

dans ce cas, votre fonction getUser sera appelée et vous obtiendrez receivingVariable= me.

2
naveen

Solution meilleure et facile.

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"webView"];
webView = (WebViewController *)vc;
webView.strWebLink = @"http://www.Google.com/";
[self.navigationController showViewController:vc sender:self];
1
iPhone 7

Utilisez le modèle Singleton:

Le modèle Singleton en génie logiciel est un modèle de conception qui garantit qu'une classe n'a qu'une seule instance et lui fournit un point d'accès global.

Comme il a une instance unique, les variables et méthodes de classe sont partagées dans l'ensemble de l'application/de l'espace de noms.

Exemple:

class Singleton {
    static let sharedInstance = Singleton()
    var studentId = 1281
}

Et vous pouvez l'utiliser n'importe où dans votre application comme ceci:

var studentId = Singleton.sharedInstance.studentId
print("Student Id: \(studentId)")
1
Alzayed

dans Swift 4.0

 // In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let vc = segue.destination as! SecondViewController
    vc.username = self.username
}

Assure-toi

segue.destination est vraiment différent ici.

1
Zumry Mohamed