Pass Variables to a new View Controller via a Subc

2019-01-15 22:19发布

问题:

I have a few moving parts in this one that I can't seem to stitch together, hopefully it is pretty straightforward.

Previous questions don't use a subclass and in this example there could be dozens of custom pins on the map and each pin passes specific variables to a new ViewController

Three Goals:

  1. Add image to custom annotation (see code below)
  2. I have a subclass named Capital, I would like to add the image in #1 and then create additional variables to hold values that will be passed to a new SecondViewController that includes (2) labels and a Picker View: for example label1 = "text1", label2 = "text2", and then grab a string from an array that contains multiple objects (i.e. the title for each row of the Picker)
  3. Once the user taps on the callout button on the custom pin we push the ViewController to a new view controller named SecondViewController and assign the values of subclass Capital that are attached to the custom pin that was tapped to the new labels and picker view in the SecondViewController

Here is my code thus far:

Subclass named 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

    }
}

Here is my code for the 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
}

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

Here is my code for the SecondViewController

import UIKit
class SecondViewController: 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"

            // continued...
        }
    }

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

Appreciate any help

回答1:

It seems that you're very close. In calloutAccessoryControlTapped, you're get getting the place name and info. I'm assuming that's what you want to pass to the second view controller, so go ahead and do so before you show it:

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    let capital = view.annotation as! Capital
    let placeName = capital.title
    let placeInfo = capital.info

    let secondViewController = sUIKeyInputUpArrowtoryboard!.instantiateViewController(withIdentifier: "SecondViewController") // I'm not sure why you're not just doing `storyboard.instantiateViewController(...); do you really have multiple storyboards floating around?
    secondViewController.placeName = placeName
    secondViewController.placeInfo = placeInfo
    show(secondViewController, sender: self)  
}

That presumes, of course, that your second view controller is has those placeName and placeInfo properties, e.g.

class SecondViewController {

    var placeName: String!
    var placeInfo: String!

    override func viewDidLoad() {
        // use placeName and placeInfo to populate UI controls as necessary
    } 
}

I confess, though, that your question has a ton of unrelated code that's hard to make sense of, so it's not clear precisely what you need to do. But the idea is clear, that calloutAccessoryControlTapped should

  • figure out what needs to get passed to the next view controller;
  • instantiate that view controller;
  • set the appropriate properties in that next view controller;
  • then show it; and
  • that second view controller should use whatever properties you set in the preceding view controller to configure it's UI.

Note, calloutAccessoryControlTapped in the first view controller cannot update the UI controls in the second view controller directly (since the controls for that view controller have not yet been hooked up to the outlets in the storyboard), but rather just passes whatever data that second view controller needs. Then that second view controller will configure its controls in its viewDidLoad.