如何在Swift 3.0中通过Segue从子类传递变量和对象 [英] How to Pass Variables and Objects from a Subclass via a Segue in Swift 3.0

查看:54
本文介绍了如何在Swift 3.0中通过Segue从子类传递变量和对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的设置:ViewController-> SecondViewControoler

Here is my setup: ViewController -> SecondViewControoler

三个目标:

  1. 将图像添加到自定义注释中(请参见下面的代码)
  2. 我有一个名为"Capital"的子类,我想在#1中添加图像,然后创建其他变量来保存值,这些值将传递给新的SecondViewController,其中包括(2)个标签和一个Picker View:示例label1 ="text1",label2 ="text2",然后从包含多个对象(即Picker每行的标题)的数组中获取一个字符串
  3. 一旦用户点击了自定义图钉上的标注按钮,我们就会将ViewController推送到名为"SecondViewController"的新ViewController上,并分配附加到自定义图钉上的子类"Capital"的值,该子图钉被窃听到新标签和SecondViewController中的Picker视图

到目前为止,这是我的代码:

Here is my code thus far:

名为"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
    }

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

Here we add the custom callout variables that are specific to the city that was pressed and push these to the 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. 另一种选择是呼叫

  1. Another option is to call

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

这将触发从ViewController进行的选择 SecondViewController.这就是您希望在情节提要中在ViewController之间移动的代码保持不变,即,您控制了从ViewController拖动到SecondViewController的过程,以创建序列并为其指定唯一ID.

which will trigger a segue from ViewController to SecondViewController. This is you like to keep the code of moving between ViewControllers in the storyboard ie, you controlled dragged from ViewController to SecondViewController to create a segue and gave it a unique id.

每个UIViewController(的子类)都继承一个函数

Every UIViewController (subclass of) inherits a function

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

将由系统调用,您可以在其中添加 顾名思义,建议实施之前准备好一切 执行特定的segue.此时下 ViewController已从情节提要板加载到内存中(但 尚未开始显示).和的"segue" *参数 "prepare(for segue: UIStoryboardSegue, sender: Any?)"实际上有一个 属性目标" 实际上是下一个ViewController.

which will be called by the system, this is where you can add implementation to as the name suggest prepare anything needed before a particular segue is performed. At this time the next ViewController have been loaded from the Storyboard into memory (but have not begin to be displayed). And the "segue"* parameter of "prepare(for segue: UIStoryboardSegue, sender: Any?)" actually has a property "destination" which is actually the next ViewController.

要小心,因为您可能对此有1个以上的选择 将ViewController更改为下一个ViewController.
所以"segue.destination"可能不是您想要的SecondViewController,如果 您有1个以上的segue设置.因为系统调用 每个"prepare(for segue: UIStoryboardSegue, sender: Any?)" segue离开当前的ViewController.确保您检查 "segue.identifier"以确保您的后续代码正在处理 与您以为自己的感觉相同.

Be Careful though, as you may have more than 1 segue from this ViewController to different next ViewController.
So "segue.destination" may not be your desired SecondViewController if you have more than 1 segue setup. Because the system calls "prepare(for segue: UIStoryboardSegue, sender: Any?)" for every segue leaving this current ViewController. Make sure you check "segue.identifier" to make sure your subsequent code are dealing with the same segue you think you are.

现在,您终于可以完成您的标题问题了. 带有指向SecondViewController的指针,您可以自由设置任何 它拥有的财产,这是您的资本的特定实例 目的.要全面了解,请使用 发件人" 参数 "performSegue(withIdentifier identifier: String, sender: Any?)"*"prepare(for segue: UIStoryboardSegue, sender: Any?)"实际上是 一样.因此,您实际上可以从中传递您喜欢的任何对象/结构 "performSegue()"转换为"prepare(for :)" 只需将发件人对象转换为 确认"segue.identifier"之后通过的类型.

Now you are finally able to do what your headline question is about. with a pointer to the SecondViewController you are free to set any property it has, which is the particular instance of your Capital object. To come full circle, the "sender" parameter of "performSegue(withIdentifier identifier: String, sender: Any?)"* and "prepare(for segue: UIStoryboardSegue, sender: Any?)" are actually the samething. So you can actually pass any object/struct you like from "performSegue()" to "prepare(for:)" Simply cast the sender object into the type you passed after confirming the "segue.identifier."


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

}

这篇关于如何在Swift 3.0中通过Segue从子类传递变量和对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆