web-dev-qa-db-fra.com

Comment passer prepareForSegue: un objet

J'ai plusieurs annotations dans une vue cartographique (avec les boutons rightCalloutAccessory). Le bouton effectuera une transition de cette mapview à une tableview. Je souhaite transmettre à la tableview un objet différent (contenant des données) en fonction du bouton de légende sur lequel l'utilisateur a cliqué.

Par exemple: (totalement maquillé)

  • annotation1 (Austin) -> données de transfert obj 1 (concernant Austin)
  • annotation2 (Dallas) -> données de transfert obj 2 (concernant Dallas)
  • annotation3 (Houston) -> transmettre les données obj 3 et ainsi de suite ... (vous voyez l'idée)

Je suis capable de détecter quel bouton de légende a été cliqué.

J'utilise prepareForSegue: pour transmettre les données obj à la destination ViewController. Étant donné que je ne peux pas faire en sorte que cet appel prenne un argument supplémentaire pour les données obj dont j'ai besoin, quels sont les moyens élégants d'obtenir le même effet (données dynamiques obj)?

Toute astuce serait appréciée.

356
chizzle

Il vous suffit de saisir une référence au contrôleur de vue cible dans la méthode prepareForSegue: et de lui transmettre tous les objets nécessaires. Voici un exemple ...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"YOUR_SEGUE_NAME_HERE"])
    {
        // Get reference to the destination view controller
        YourViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyObjectHere:object];
    }
}

RÉVISION: Vous pouvez également utiliser la méthode performSegueWithIdentifier:sender: pour activer la transition vers une nouvelle vue basée sur une sélection ou une pression sur un bouton.

Par exemple, considérez que j'avais deux contrôleurs de vue. Le premier contient trois boutons et le second doit savoir lequel de ces boutons a été enfoncé avant la transition. Vous pouvez connecter les boutons jusqu’à un IBAction dans votre code qui utilise la méthode performSegueWithIdentifier:, comme ceci ...

// When any of my buttons are pressed, Push the next view
- (IBAction)buttonPressed:(id)sender
{
    [self performSegueWithIdentifier:@"MySegue" sender:sender];
}

// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"MySegue"]) {

        // Get destination view
        SecondView *vc = [segue destinationViewController];

        // Get button tag number (or do whatever you need to do here, based on your object
        NSInteger tagIndex = [(UIButton *)sender tag];

        // Pass the information to your destination view
        [vc setSelectedButton:tagIndex];
    }
}

EDIT: La demande de démonstration que j'ai jointe à l'origine a maintenant six ans, je l'ai donc supprimée pour éviter toute confusion.

672
Simon

Parfois, il est utile d'éviter de créer une dépendance à la compilation entre deux contrôleurs de vue. Voici comment vous pouvez le faire sans vous soucier du type de contrôleur de vue de destination:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController respondsToSelector:@selector(setMyData:)]) {
        [segue.destinationViewController performSelector:@selector(setMyData:) 
                                              withObject:myData];
    } 
}

Donc, tant que votre contrôleur de vue de destination déclare une propriété publique, par exemple:

@property (nonatomic, strong) MyData *myData;

vous pouvez définir cette propriété dans le contrôleur de vue précédent, comme décrit ci-dessus.

82
Macondo2Seattle

Dans Swift 4.2 je ferais quelque chose comme ça:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let yourVC = segue.destination as? YourViewController {
        yourVC.yourData = self.someData
    }
}
20
Remy Cilia

J'ai un classe d'expéditeur, comme ceci

@class MyEntry;

@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end

@implementation MySenderEntry
@end

J'utilise ceci classe d'expéditeur pour passer des objets à prepareForSeque:sender:

-(void)didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
    MySenderEntry *sender = [MySenderEntry new];
    sender.entry = [_entries objectAtIndex:indexPath.row];
    [self performSegueWithIdentifier:SEGUE_IDENTIFIER_SHOW_ENTRY sender:sender];
}

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_SHOW_ENTRY]) {
        NSAssert([sender isKindOfClass:[MySenderEntry class]], @"MySenderEntry");
        MySenderEntry *senderEntry = (MySenderEntry*)sender;
        MyEntry *entry = senderEntry.entry;
        NSParameterAssert(entry);

        [segue destinationViewController].delegate = self;
        [segue destinationViewController].entry = entry;
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_HISTORY]) {
        // ...
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_FAVORITE]) {
        // ...
        return;
    }
}
16
neoneye

Je suis tombé sur cette question lorsque j'essayais d'apprendre à transmettre des données d'un contrôleur View à un autre. J'ai besoin de quelque chose de visuel pour m'aider à apprendre, alors cette réponse est un complément aux autres déjà présents. C'est un peu plus général que la question initiale mais il peut être adapté au travail.

Cet exemple de base fonctionne comme ceci:

enter image description here

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.

Premier contrôleur de vue

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!
    }

}

Deuxième contrôleur de vue

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
    }

}

Se souvenir de

  • Faire la transition par control en cliquant sur le bouton et en le glissant vers le contrôleur Second View.
  • Branchez les prises pour la UITextField et la UILabel.
  • Définissez les premier et second contrôleurs de vue sur les fichiers Swift appropriés dans IB.

La source

Comment envoyer des données via segue (Swift) (tutoriel YouTube)

Voir également

Contrôleurs de vue: transmission de données et transmission de données (réponse complète)

14
Suragch

Pour Swift utilisez ceci,

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var segueID = segue.identifier

    if(segueID! == "yourSegueName"){

        var yourVC:YourViewController = segue.destinationViewController as YourViewController

        yourVC.objectOnYourVC = setObjectValueHere!

    }
}
5
Zaid Pathan

J'ai mis en place une bibliothèque avec une catégorie sur UIViewController qui simplifie cette opération. Fondamentalement, vous définissez les paramètres que vous souhaitez transmettre dans un NSDictionary associé à l'élément d'interface utilisateur qui effectue la séquence. Cela fonctionne aussi avec les séquences manuelles.

Par exemple, vous pouvez faire

[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

pour un segue manuel ou créer un bouton avec un segue et utiliser

[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

Si le contrôleur de vue de destination n'est pas compatible avec le codage clé-valeur pour une clé, rien ne se produit. Cela fonctionne aussi avec les valeurs-clés (utile pour les segments déroulés). Vérifiez-le ici https://github.com/stefanomondino/SMQuickSegue

4
Stefano Mondino

Ma solution est similaire.

// In destination class: 
var AddressString:String = String()

// In segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if (segue.identifier == "seguetobiddetailpagefromleadbidder")
    {
        let secondViewController = segue.destinationViewController as! BidDetailPage
        secondViewController.AddressString = pr.address as String
    }
}
2
A.G

Utilisez simplement cette fonction.

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    let VC = segue.destination as! DestinationViewController
   VC.value = self.data

}
1
Parth Barot

J'ai utilisé cette solution pour pouvoir garder l'invocation de la segue et la communication de données dans la même fonction:

private var segueCompletion : ((UIStoryboardSegue, Any?) -> Void)?

func performSegue(withIdentifier identifier: String, sender: Any?, completion: @escaping (UIStoryboardSegue, Any?) -> Void) {
    self.segueCompletion = completion;
    self.performSegue(withIdentifier: identifier, sender: sender);
    self.segueCompletion = nil
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    self.segueCompletion?(segue, sender)
}

Un cas d'utilisation serait quelque chose comme:

func showData(id : Int){
    someService.loadSomeData(id: id) {
        data in
        self.performSegue(withIdentifier: "showData", sender: self) {
            storyboard, sender in
            let dataView = storyboard.destination as! DataView
            dataView.data = data
        }
    }
}

Cela semble fonctionner pour moi, cependant, je ne suis pas sûr à 100% que les fonctions perform et prepare soient toujours exécutées sur le même thread.

0
dannrob