Reputation: 309
Here is my setup: ViewController -> SecondViewControoler
Three Goals:
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 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"
continued...
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
cityName = row
}
}
Appreciate any help
Upvotes: 1
Views: 986
Reputation: 179
Another option is to call
"func performSegue(withIdentifier identifier: String, sender: Any?)"
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.
Every UIViewController (subclass of) inherits a function
"func prepare(for segue: UIStoryboardSegue, sender: Any?)"
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.
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.
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
}
Upvotes: 4
Reputation: 2818
Create a reference to the class where you want to pass data to AKA your destination class
`let vc = self.storyboard!.instantiateViewController(withIdentifier: "Class Identifier") as! YourDestinationClass`
Then you will have access to all the objects inside YourDestinationClass
by using vc
Upvotes: 0
Reputation: 131481
Working off of Rob's suggestion, but passing the Capital
object in sender rather than the view, your calloutAccessoryControlTapped might look like this:
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
}
Upvotes: 1