如何在Swift 3.0中通过Segue传递variables和对象

这是我的设置:ViewController – > SecondViewControoler

三目标:

  1. 添加图像到自定义注释(见下面的代码)
  2. 我有一个名为“资本”的子类,我想在#1中添加图像,然后创build额外的variables来保存将传递到一个新的SecondViewController,其中包括(2)标签和select器视图的值:例如label1 = “text1”,label2 =“text2”,然后从包含多个对象的数组中获取一个string(即Picker的每一行的标题)
  3. 一旦用户点击定制引脚上的标注button,我们将ViewController推送到名为“SecondViewController”的新ViewController,并将附加到自定义引脚上的子类“Capital”的值分配给新标签和Picker View在SecondViewController中

这是我迄今为止的代码:

名为“Capital.swift”的子类

import MapKit import UIKit class Capital: NSObject, MKAnnotation { var title: String? var coordinate: CLLocationCoordinate2D var info: String // here we would add the custom image in Goal #1 // here we would add the (2) values for label1 and label2 in Goal #2 // here we would add the array that contains multiple object in Goal #2 init(title: String, coordinate: CLLocationCoordinate2D, info: String) { self.title = title self.coordinate = coordinate self.info = info // add additional lines as needed } } 

这是我的ViewController.swift的代码

 import MapKit import UIKit class ViewController: UIViewController, MKMapViewDelegate { @IBOutlet var mapView: MKMapView! override func viewDidLoad() { super.viewDidLoad() let london = Capital(title: "London", coordinate: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), info: "Home to the 2012 Summer Olympics.") let oslo = Capital(title: "Oslo", coordinate: CLLocationCoordinate2D(latitude: 59.95, longitude: 10.75), info: "Founded over a thousand years ago.") let paris = Capital(title: "Paris", coordinate: CLLocationCoordinate2D(latitude: 48.8567, longitude: 2.3508), info: "Often called the City of Light.") let rome = Capital(title: "Rome", coordinate: CLLocationCoordinate2D(latitude: 41.9, longitude: 12.5), info: "Has a whole country inside it.") let washington = Capital(title: "Washington DC", coordinate: CLLocationCoordinate2D(latitude: 38.895111, longitude: -77.036667), info: "Named after George himself.") mapView.addAnnotations([london, oslo, paris, rome, washington]) } func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { let identifier = "Capital" if annotation is Capital { if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) { annotationView.annotation = annotation return annotationView } else { let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:identifier) annotationView.isEnabled = true annotationView.canShowCallout = true let btn = UIButton(type: .detailDisclosure) annotationView.rightCalloutAccessoryView = btn //annotationView.image = UIImage(named: "#imageLiteral(resourceName: ",pin,")") return annotationView } } return nil } 

在这里,我们添加特定于城市的自定义标注variables,并将其推送到SecondViewController

 func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) { let capital = view.annotation as! Capital let placeName = capital.title let placeInfo = capital.info //Add custom image + (2) labels + and the array that contains multiple objects to be passed to the Picker 'view in the SecondViewController // Upon the User tapping the above button we push all the variables stored in Capital attached to the current city pin that was pressed to the new SecondViewController // Send the View Controller to the SecondViewController programically let SecondViewController = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") self.show(SecondViewController!, sender: nil) } } 

这是我的代码为SecondViewController

 import UIKit class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource { @IBOutlet weak var pickerView: UIPickerView! var cityName = 0 //the values here are pulled from the custom pin that was pressed in the previous ViewController var Array = ["object1 from custom pin","object2 from custom pin,","object3 from custom pin"] @IBOutlet weak var label1: UILabel! @IBOutlet weak var label2: UILabel! override func viewDidLoad() { super.viewDidLoad() pickerView.delegate = self pickerView.dataSource = self } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return Array[row] } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return Array.count } func numberOfComponents(in pickerView: UIPickerView) -> Int { return 1 } @IBAction func submit(_ sender: Any) { if (cityName == 0){ label1.text = "object1 from custom pin" } else if(cityName == 1){ label1.text = "object2 from custom pin" } else{ label1.text = "object3 from custom pin" 

继续…

  } } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { cityName = row } } 

感谢任何帮助

  1. 另一个select是打电话

     "func performSegue(withIdentifier identifier: String, sender: Any?)" 

    这将触发从ViewController segView到SecondViewController。 这是你想保持在ViewController之间移动的故事板的代码,即你控制从ViewController拖到SecondViewController创build一个segue,并给它一个唯一的ID。

  2. 每个UIViewController(的子类)都inheritance一个函数

     "func prepare(for segue: UIStoryboardSegue, sender: Any?)" 

    这将被系统调用,这是你可以添加实现的地方,正如名字所暗示的那样,在执行某个特定的segue之前准备任何需要的东西。 此时下一个ViewController已经从Storyboard加载到内存中(但还没有开始显示)。 而且, "prepare(for segue: UIStoryboardSegue, sender: Any?)"的“segue”*参数实际上有一个属性“destination” ,它实际上是下一个ViewController。

    但要小心 ,因为从这个ViewController到不同的下一个ViewController可能有多于一个segue。
    所以如果你有超过1个segue设置,那么"segue.destination"可能不是你想要的SecondViewController。 因为系统调用"prepare(for segue: UIStoryboardSegue, sender: Any?)"每个segue离开这个当前的ViewController。 确保你检查"segue.identifier" ,以确保你的后续代码正在处理你认为你是同一个segue。

  3. 现在你终于可以做你的标题问题了。 使用指向SecondViewController的指针,您可以自由设置它的任何属性,这是您的Capital对象的特定实例。 要实现完整的循环, "performSegue(withIdentifier identifier: String, sender: Any?)"*"prepare(for segue: UIStoryboardSegue, sender: Any?)"“sender”参数实际上是相同的。 所以你实际上可以将你所喜欢的任何对象/结构体从“performSegue()”传递给“prepare(for :)”。只要将sender对象转换为确认了“segue.identifier”后传入的types即可。


 func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) { let capital = view.annotation as! Capital let placeName = capital.title let placeInfo = capital.info // Option 1 perform segue.performSegue(withIdentifier: "SegueToSecondID", sender: capital) //Option 2 programmatically create SecondViewController and show. let SecondViewController = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") SecondViewController.capital = capital self.show(SecondViewController!, sender: nil) } // If you are doing option 1 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "SegueToSecondID" && sender is Capital { let destination = segue.destination as SeconViewController destination.capital = sender } } 

 class SecondViewController { //........ var capital: Capital? //Up to you if you want this as an optional } 

关注Rob的build议,但是将Capital对象传递给发送者而不是视图,你的calloutAccessoryControlTapped可能看起来像这样:

 func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) { guard let capital = view.annotation as? Capital else { return } performSegue(withIdentifier: "segue1", sender: capital) } func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let destination = segue.destination as? SecondViewController, let capital = sender as? Capital else { return } destination.capital = capital //Assuming SecondViewController has a capital property } 

创build一个你想传递数据到你的目标类的类的引用

  `let vc = self.storyboard!.instantiateViewController(withIdentifier: "Class Identifier") as! YourDestinationClass` 

然后你将有权使用vc访问YourDestinationClass的所有对象