web-dev-qa-db-fra.com

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

J'essaie de transmettre des données RETOUR AU précédent viewController. 

Est-ce que quelqu'un sait comment transmettre des données de ViewController B à ViewController A? Je souhaite donc qu'une chaîne passe de BIDAddTypeOfDealViewController à BIDDCCreateViewController. Un utilisateur édite viewController B et je souhaite que les données modifiées soient de nouveau affichées dans ViewController A, où je les utilise ensuite. 

J'utilise la section 'transmission de données' de cette réponse . Ce qui différencie le mien: les points 3 et 6 mentionnent simplement le moment où les vues sont affichées, c'est pourquoi j'ai mis ce code dans viewWillDisappear Je pense que cela est correct? Également au point 6, je n’ai pas initialisé avec la pointe car elle est ancienne. J'utilise des storyboards. Et je n’ai pas ajouté cette dernière ligne car je ne pense pas que j’aurais à la pousser. Appuyer sur un bouton de mon story-board me fait déjà avancer. 

Je pense que le problème peut survenir dans BIDDCCreateViewController, j'ai la méthode mais je ne peux pas l'exécuter. Pour exécuter une méthode, il faut utiliser [méthode auto]. Je suis incapable de faire ça. Eh bien, c'est ce que je devine. 

Il compile et fonctionne bien mais rien n’est enregistré, donc je ne sais pas si cela fonctionne. 

UPDATE: Je ne parviens pas à exécuter la méthode 'sendDataToA'. 

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

 @interface BIDDCCreateViewController : UIViewController
 @property (strong, nonatomic) NSString *placeId;
- (IBAction)gotoBViewController:(id)sender;
@end


#import "BIDDCCreateViewController.h"
#import "BIDAddTypeOfDealViewController.h"

@implementation BIDDCCreateViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSLog(@"SUCCESSFULLY PASSED PLACE ID: %@", self.placeId);
}

-(void)sendDataToA:(NSString *)myStringData
{

    NSLog(@"Inside sendDataToA");
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Your string Data Showing" message:myStringData delegate:self cancelButtonTitle:@"Ok " otherButtonTitles:nil];
    [alert show];
}

- (IBAction)gotoBViewController:(id)sender {
    NSLog(@"pressed");
    BIDAddTypeOfDealViewController *bidAddType = [[BIDAddTypeOfDealViewController alloc]init];
    bidAddType.delegate = self;

}
@end


@protocol senddataProtocol <NSObject>
-(void)sendDataToA:(NSString *)myStringData;
@end

#import <UIKit/UIKit.h>
@interface BIDAddTypeOfDealViewController : UIViewController <UITextFieldDelegate>//Using this delegate for data a user inputs
@property(nonatomic,assign)id delegate;
//other textfield outlets not relevant
- (IBAction)chooseDiscountDeal:(id)sender;
@end

#import "BIDAddTypeOfDealViewController.h"

@interface BIDAddTypeOfDealViewController ()

@end

@implementation BIDAddTypeOfDealViewController
@synthesize delegate;

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

- (void)viewDidLoad
{
    [super viewDidLoad];
}

-(void)viewWillDisappear:(BOOL)animated
{
    [delegate sendDataToA:@"Apple"];
}
@end
48
Anthony

Vous pouvez utiliser un délégué. Donc, dans votre ViewController B, vous devez créer un protocole qui renvoie les données à votre ViewController A. Votre ViewController A deviendrait un délégué de ViewController B. 

Si vous êtes nouveau dans Objective C, veuillez regarder Qu'est-ce que Délégué .

Créer un protocole dans ViewControllerB.h:

#import <UIKit/UIKit.h>

@protocol senddataProtocol <NSObject>

-(void)sendDataToA:(NSArray *)array; //I am thinking my data is NSArray, you can use another object for store your information. 

@end

@interface ViewControllerB : UIViewController

@property(nonatomic,assign)id delegate;

ViewControllerB.m

@synthesize delegate;
-(void)viewWillDisappear:(BOOL)animated
{
     [delegate sendDataToA:yourdata];

}

dans votre ViewControllerA: lorsque vous accédez à ViewControllerB 

ViewControllerA *acontollerobject=[[ViewControllerA alloc] initWithNibName:@"ViewControllerA" bundle:nil];
acontollerobject.delegate=self; // protocol listener
[self.navigationController pushViewController:acontollerobject animated:YES];

et définissez votre fonction: 

-(void)sendDataToA:(NSArray *)array
{
   // data will come here inside of ViewControllerA
}

Édité:

Vous pouvez voir cet exemple: Comment transmettre des données à un contrôleur de vue précédent: Lien du tutoriel

88
Erhan Demirci

Une méthode plus courte et plus simple que protocole/délégué consiste à créer une fermeture:

Pour renvoyer une chaîne dans mon cas . Dans ViewControllerA:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let viewControllerB = segue.destination as? ViewControllerB {
        viewControllerB.callback = { message in
            //Do what you want in here!
        }
    }
}

Dans ViewControllerB:

var callback : ((String) -> Void)?

@IBAction func done(sender: AnyObject) {
    callback?("Hi")
    self.dismiss(animated: true, completion: nil)
}
51
Heinrisch

Swift: Renvoyer des données en utilisant le motif délégué

Ma réponse complète qui couvre la transmission de données dans les deux sens est ici . Ma réponse expliquant le modèle de délégué est ici .

Pour transmettre les données du second contrôleur de vue au premier, vous utilisez un 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 prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController 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: UIButton) {

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

        // go back to the previous view controller
        self.navigationController?.popViewControllerAnimated(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.

40
Suragch

Edit: Utilisez la solution de @ Erhan ci-dessus. Pas celui-ci. Ce n'est pas une bonne solution.

CA aidera. Ecrivez ceci dans votre ViewControllerB. 

    // Get array of current navigation stack
    NSArray *arrayViewControllers = [self.navigationController viewControllers];

    // Get previous viewController object from it
    YOUR_VIEW_CONTROLLER_NAME *objViewController = (YOUR_VIEW_CONTROLLER_NAME *)[arrayViewControllers objectAtIndex:arrayViewControllers.count-2];

    // For safety this check is needed. whether it the class that you want or not.
    if ([objViewController isKindOfClass:[YOUR_VIEW_CONTROLLER_NAME class]])
    {
        // Access properties of YOUR_VIEW_CONTROLLER_NAME here
        objViewController.yourProperty = YOUR_VALUE;
    }
2
Akshit Zaveri

Comme Erhan Demirci a répondu, vous pouvez utiliser des délégués. Les délégués sont utiles lorsque vous souhaitez transmettre des données à un seul contrôleur de vue.

NSNotificationCenter est un autre moyen pratique de transférer des données entre contrôleurs de vue/objets. Ceci est très utile pour la diffusion de données dans l'application.

lire la documentation ici .

1
Abdullah Umer

Le délégué personnalisé est la meilleure option pour déplacer des données, mais vous pouvez également essayer.

Vous pouvez utiliser NSUserDefaults pour déplacer les données où bon vous semble.

Swift 3 Code

UserDefaults.standard.set(<Value>, forKey: <Key>) 
// To set data

UserDefaults.standard.object(forKey: <Key>) 
// To get data

Vous pouvez également utiliser NSNotification pour déplacer des données.

NotificationCenter.default.post(name: Notification.Name(rawValue: "refresh"), object: myDict) 

NotificationCenter.default.addObserver(self, selector: #selector(refreshList(_:)), name: NSNotification.Name(rawValue: "refresh"), object: nil)
1
Saurabh Sharma

Il y a protocole il y a fermeture. Avec la fermeture, nous devons éviter les fuites de mémoire en utilisant un moi faible (ou un moi sans propriétaire). Avec le protocole, il y aurait un contrôleur ViewController que vous souhaitez "surveiller", avec des dizaines de délégués à implémenter. Voici une autre solution simple à Swift:

Dans un nouveau fichier ou un fichier existant (par exemple: UIViewController+Extensions.Swift), créez ce protocole:

protocol ViewControllerBackDelegate: class {
    func back(from viewController: UIViewController)
}

Dans viewController de LEVEL-2, où vous souhaitez un rappel lorsque vous appuyez sur Retour à partir de:

class LevelTwoViewController: UIViewController {
    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: ViewControllerBackDelegate? = nil

    override func willMove(toParentViewController parent: UIViewController?) {
        super.willMove(toParentViewController: parent)
        if (parent == nil) {
            delegate?.back(from: self)
        }
    }
}

Puisque delegate est facultatif, vous pouvez ajouter ce code à une classe de base de vos contrôleurs de vue. J'ajouterais là où il faut.

Dans votre viewController LEVEL-1, supposez que vous appeliez LEVEL-2 via une transition dans Storyboard:

class LevelOneViewController: UIViewController {
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "Go to Level 2") {
            if let vc = segue.destination as? LevelTwoViewController {
                vc.selectedItems = self.selectedItems // passing data-in
                vc.delegate = self
            }
        }
        // repeat `if` for another sub-level view controller
    }
}

extension LevelOneViewController: ViewControllerBackDelegate {    
    func back(from viewController: UIViewController) {
        if let vc = viewController as? LevelTwoViewController {
            self.selectedItems = vc.selectedItems
            // call update if necessary
        }
        // repeat `if` for another sub-level view controller
    }
}
  • un seul protocole est requis.
  • une seule extension par viewController de premier niveau.
  • aucune modification à viewController de sous-niveau si plus/moins de données doivent être renvoyées
  • gérer les données comme les données dans prepare(for:sender:)
0
John Pang