Comment passer prepareForSegue: un objet
j'ai beaucoup d'annotations dans un mapview (avec les boutons rightCalloutAccessory
). Le bouton va effectuer une transition de ce mapview
à un tableview
. Je veux passer le tableview
un objet différent (qui contient des données) en fonction du bouton callout qui a été cliqué.
par exemple: (entièrement confectionné)
- annotation1 (Austin) -> col de données obj 1 (Austin)
- annotation2 (Dallas) - > données sur les laissez-passer obj 2 (Dallas)
- annotation3 (Houston) -> col de données obj 3 et ainsi de suite... (vous avez l' idea)
je suis capable de détecter le bouton d'appel qui a été cliqué.
j'utilise prepareForSegue
: pour passer les données obj à la destination ViewController
. Puisque je ne peux pas faire cet appel prendre un argument supplémentaire pour les données obj j'ai besoin, quels sont quelques moyens élégants pour atteindre le même effet (données obj dynamique)?
N'importe quel conseil serait apprécié.
10 réponses
saisissez simplement une référence au contrôleur de vue cible dans la méthode prepareForSegue:
et passez tous les objets dont vous avez besoin. 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érer que j'avais deux contrôleurs de vue. Le premier contient trois boutons et le second doit savoir lequel de ces boutons a été pressée avant la transition. Vous pouvez brancher 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: L'application de démonstration que j'ai à l'origine joint a maintenant six ans, donc je l'ai enlevé pour éviter toute confusion.
la réponse acceptée n'est pas la meilleure façon de le faire, car elle crée une dépendance inutile 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];
}
}
aussi longtemps que votre contrôleur de vue de destination déclare un bien public, par exemple:
@property (nonatomic, strong) MyData *myData;
vous pouvez définir cette propriété dans le contrôleur de vue précédent comme je l'ai décrit ci-dessus.
dans Swift je ferais quelque chose comme ça:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let yourVC = segue.destinationViewController as? YourViewController {
yourVC.yourData = self.someData
}
}
j'ai un "151940920 expéditeur" classe , comme cette
@class MyEntry;
@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end
@implementation MySenderEntry
@end
j'utilise ce "151940920 expéditeur" classe pour le passage 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;
}
}
j'ai rencontré cette question quand j'essayais d'apprendre comment passer des données d'un contrôleur de vue à un autre. J'ai besoin de quelque chose de visuel pour m'aider à apprendre, donc cette réponse est un supplément aux autres déjà ici. Elle est un peu plus générale que la question initiale, mais elle peut être adaptée au travail.
cet exemple de base fonctionne comme ceci:
l'idée est de passer une chaîne du champ texte dans le Controller de la première vue au label dans le Controller de la deuxième vue.
Premier-Vue-Contrôleur
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!
}
}
Seconde Vue-Contrôleur
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
}
}
Rappelez-vous
- faire la séquence par control en cliquant sur le bouton et en le drainant vers le contrôleur de la deuxième vue.
- le raccordement de la les prises pour le
UITextField
et leUILabel
. - définit les contrôleurs first et second View aux fichiers Swift appropriés dans IB.
Source
Comment envoyer des données à travers des enchaînements (swift) (YouTube tutoriel)
Voir aussi
Afficher les Contrôleurs: la transmission des données vers l'avant et la transmission des données en arrière (fuller répondre)
j'ai implémenté une bibliothèque avec une catégorie sur UIViewController qui simplifie cette opération. Fondamentalement, vous définissez les paramètres que vous voulez passer dans un Nsdiction associé à L'item UI qui exécute la séquence. Il fonctionne aussi avec des séquences manuelles.
par exemple, vous pouvez faire
[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];
pour une séquence manuelle ou créer un bouton avec une séquence et utiliser
[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];
si contrôleur de vue de destination n'est pas valeur-clé de codage conforme pour une clé, rien ne se passe. Il fonctionne avec des valeurs-clés aussi (utile pour décompresser des segments). Découvrez-le ici https://github.com/stefanomondino/SMQuickSegue
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!
}
}
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
}
}
j'ai utilisé cette solution pour garder l'invocation de la séquence 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 sont toujours exécutées sur le même thread.
il suffit d'utiliser 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
}