Cómo pasar prepareForSegue: un objeto

Tengo muchas anotaciones en una vista de rightCalloutAccessory (con botones de rightCalloutAccessory ). El botón realizará una transición de esta vista de tableview a una vista de tableview . Quiero pasar la vista de tableview un objeto diferente (que contiene datos) dependiendo del botón de llamada en el que se hizo clic.

Por ejemplo: (totalmente inventado)

  • anotación1 (Austin) -> pasar datos obj 1 (relevante para Austin)
  • annotation2 (Dallas) -> pasar datos obj 2 (relevante para Dallas)
  • annotation3 (Houston) -> pasar datos obj 3 y así sucesivamente … (se entiende la idea)

Puedo detectar en qué botón de llamada se hizo clic.

Estoy usando prepareForSegue : para pasar el obj de datos al ViewController destino. Como no puedo hacer esta llamada, tome un argumento adicional para los datos que necesito, ¿cuáles son algunas formas elegantes de lograr el mismo efecto (datos dynamics obj)?

Cualquier consejo sería apreciado.

Simplemente tome una referencia al controlador de vista de destino en el método prepareForSegue: y pase todos los objetos que necesite allí. Aquí hay un ejemplo …

 - (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]; } } 

REVISIÓN: También puede usar el performSegueWithIdentifier:sender: para activar la transición a una nueva vista basada en una selección o presionar un botón.

Por ejemplo, considere que tengo dos controladores de vista. El primero contiene tres botones y el segundo necesita saber cuál de esos botones se ha pulsado antes de la transición. Puede conectar los botones hasta una IBAction en su código que usa el método performSegueWithIdentifier: así …

 // 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]; } } 

EDITAR: La aplicación de demostración que adjunté originalmente tiene ahora seis años, así que la eliminé para evitar confusiones.

La respuesta aceptada no es la mejor manera de hacerlo, porque crea una dependencia de tiempo de comstackción innecesaria entre dos controladores de vista. Así es cómo puede hacerlo sin preocuparse por el tipo de controlador de vista de destino:

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

Siempre que su controlador de vista de destino declare una propiedad pública, por ejemplo:

 @property (nonatomic, strong) MyData *myData; 

puede establecer esta propiedad en el controlador de vista anterior como describí anteriormente.

En Swift, haría algo así:

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

Tengo una clase de remitente , como esta

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

Uso esta clase de remitente para pasar objetos a 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; } } 

Me encontré con esta pregunta cuando estaba tratando de aprender a pasar datos de un Controlador de Vista a otro. Sin embargo, necesito algo visual que me ayude a aprender, por lo que esta respuesta es un complemento para los demás que ya están aquí. Es un poco más general que la pregunta original, pero puede adaptarse para funcionar.

Este ejemplo básico funciona así:

enter image description here

La idea es pasar una cadena del campo de texto en el Controlador de primera vista a la etiqueta en el Controlador de segunda vista.

Primer controlador de vista

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

Controlador de segunda vista

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

Recuerda

  • Haga la transición con el control haciendo clic en el botón y arrastrándolo hacia el controlador de segunda vista.
  • UITextField las tomas de UITextField y UILabel .
  • Establezca el primer y segundo controlador de vista en los archivos Swift apropiados en IB.

Fuente

Cómo enviar datos a través de segue (swift) (tutorial de YouTube)

Ver también

Controladores de vista: pasar datos hacia adelante y pasar datos de vuelta (respuesta más completa)

Implementé una biblioteca con una categoría en UIViewController que simplifica esta operación. Básicamente, establece los parámetros que desea ignorar en un NSDictionary asociado al elemento de UI que está realizando el cambio. Funciona con segues manuales también.

Por ejemplo, puedes hacer

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

para una transición manual o crear un botón con una transición y uso

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

Si el controlador de vista de destino no es compatible con la encoding de clave-valor para una clave, no ocurre nada. También funciona con pares clave-valor (útil para desenrollar los segmentos). Compruébelo aquí https://github.com/stefanomondino/SMQuickSegue

Para Swift usa esto,

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { var segueID = segue.identifier if(segueID! == "yourSegueName"){ var yourVC:YourViewController = segue.destinationViewController as YourViewController yourVC.objectOnYourVC = setObjectValueHere! } } 

Mi solución es similar.

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

Utilicé esta solución para poder mantener la invocación de la transición y la comunicación de datos dentro de la misma función:

 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 caso de uso sería algo así como:

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

Esto parece funcionar para mí, sin embargo, no estoy 100% seguro de que las funciones de ejecución y preparación siempre se ejecuten en el mismo hilo.

Solo usa esta función.

  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 }