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é)
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.
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.
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.
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
}
}
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;
}
}
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:
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.
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!
}
}
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
}
}
UITextField
et la UILabel
.Comment envoyer des données via segue (Swift) (tutoriel YouTube)
Contrôleurs de vue: transmission de données et transmission de données (réponse complète)
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!
}
}
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
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
}
}
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
}
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.