How to pass firebase data information to another viewcontroller when mapview annotation is clicked? - swift

I know similar questions have been asked many times before. Just can't find one solution that fits my need. Please help
I have been trying to load information from firebase onto mapview. I am able to append all the information view map annotationviews. however what I want to do is pass the firebase data to a new viewcontroller when the map annotationviews are clicked. I am able to segue into another viewcontroller when clicking the annotations, but the wrong firebase data is loaded
Code I have tried thus far:
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
observeGeofire()
}
func observeGeofire() {
let dataRef = Database.database().reference().child("Shoutout")
dataRef.observeSingleEvent(of: .value, with: { (snapshot) in
for snap in snapshot.children {
let postSnap = snap as! DataSnapshot
if let dict = postSnap.value as? [String: AnyObject] {
let Lat = dict["lat"] as! CLLocationDegrees
let Long = dict["long"] as! CLLocationDegrees
let EVENT = dict["Event Type"] as? String
let Radmap = self.Rad
var annotations = MKPointAnnotation()
annotations.coordinate = CLLocationCoordinate2D(latitude: Lat, longitude: Long)
annotations.title = dict["title"] as? String
let loc = CLLocation(latitude: Lat, longitude: Long)
let distanceFromUser = (self.Location.distance(from: loc))/1000
let span = MKCoordinateSpanMake(0.25, 0.25)
if distanceFromUser < Radmap && EVENT! == self.sovcCET {
self.mapView.addAnnotation(annotations)
print("testing text for \(self.sovcCET)")
} else if distanceFromUser < Radmap && self.sovcCET == "All Events"{
self.mapView.addAnnotation(annotations)
} else if distanceFromUser < Radmap && self.sovcCET == "Choose Event" {
self.mapView.addAnnotation(annotations)
} else {
print("failed test")
}
}
}
})
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.pinTintColor = UIColor.red
pinView?.canShowCallout = true
let smallSquare = CGSize(width: 30, height: 30)
let button = UIButton(frame: CGRect(origin: CGPoint(x: 0,y :0), size: smallSquare))
let rightButton = UIButton(type: .contactAdd)
rightButton.tag = annotation.hash
pinView?.animatesDrop = true
pinView?.canShowCallout = true
pinView?.rightCalloutAccessoryView = rightButton
pinView?.leftCalloutAccessoryView = button
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView,
calloutAccessoryControlTapped control: UIControl) {
//mapToDetails
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "mapToDetails", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mapToDetails" {
if let destination = segue.destination as? shoutoutDetailViewController {
destination.shoutoutSelected = ShoutoutSelected
}
}
}
ShoutoutSelected is actually an instantiation of a class Shoutout containing multiple variable as shown below:
class Shoutout: NSObject {
// CLLocationDegrees
var event: String?
var when: String?
var Place: String?
var details: String?
var timestamp: NSNumber?
var whenTimeStamp: NSNumber?
var picsImageUrl: String?
var fromId: String?
var lat: CLLocationDegrees?
var long: CLLocationDegrees?
var title: String?
var subtitle: String?
var shoutoutId: String?
var distance: Double?
var tit: String?
var capt: String?
init(dictionary: [String: Any]) {
self.event = dictionary["Event Type"] as? String
self.when = dictionary["Date and Time"] as? String
self.whenTimeStamp = dictionary["Date and Time"] as? NSNumber
self.Place = dictionary["place"] as? String
self.details = dictionary["details"] as? String
self.timestamp = dictionary["TIMESTAMP"] as? NSNumber
self.picsImageUrl = dictionary["postPicUrl"] as? String
self.fromId = dictionary["FROM"] as? String
self.lat = dictionary["lat"] as? CLLocationDegrees
self.long = dictionary["long"] as? CLLocationDegrees
self.title = dictionary["title"] as? String
self.subtitle = dictionary["subtitle"] as? String
self.shoutoutId = dictionary ["ResponseID"] as? String
self.tit = dictionary ["Event Title"] as? String
self.capt = dictionary ["Captions"] as? String
}
func shouterPartnerId() -> String? {
return fromId
}
func soid() -> String? {
return shoutoutId
}
}
Thanks again

you can use below code instead of prepare segue
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView,
calloutAccessoryControlTapped control: UIControl) {
let vc = self.storyboard?.instantiateViewController(withIdentifier:
"DestinationViewController") as! DestinationViewController
vc.shoutoutSelected = ShoutoutSelected
self.navigationController?.pushViewController(vc, animated: true)
}

When using performSegue, performSegue(withIdentifier: "mapToDetails", sender: self) you can send your object in sender . So instead of sending sender : self try sender: ShoutoutSelected
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView,
calloutAccessoryControlTapped control: UIControl) {
//mapToDetails
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "mapToDetails", sender: ShoutOutSelected)
}
}
Now in prepareForSegue, you can retrieve the value of sender and pass it to the destination controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mapToDetails" {
if let destination = segue.destination as? shoutoutDetailViewController {
destination.shoutoutSelected = sender as! Int // here sender = ShoutoutSelected, downcast it from Any to your desired type. I am considering destination.shoutoutSelected is of Int type.
}
}
}

Related

Can't fetch custom model from mapview did change state function

I'm trying to print out my post model when the drag state has finished but for some reason, it won't print out anything. I have attached my model which is workings fine with the viewFor function. Thanks for any help in advance.
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.ending {
if let annon = view.annotation?.coordinate as? MyAnno {
print(annon.post?.id) //Not working
view.dragState = MKAnnotationViewDragState.none
}
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView = MKMarkerAnnotationView()
guard let annotation = annotation as? MyAnno else {return nil}
var identifier = ""
if let dequedView = mapView.dequeueReusableAnnotationView(
withIdentifier: identifier)
as? MKMarkerAnnotationView {
annotationView = dequedView
} else {
annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
}
Model:
class MyAnno: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var post: Post?
var title: String?
init(post: Post, title: String?, subtitle: String?, latitude:CLLocationDegrees, longitude:CLLocationDegrees) {
self.coordinate = CLLocationCoordinate2DMake(latitude, longitude)
self.title = title
}
}
I think there is a .coordinate which is not needed
Please change this line:
if let annon = view.annotation?.coordinate as? MyAnno {
to
if let annon = view.annotation as? MyAnno {

How can I use the generic Apple Maps pins for locations in MapKit, rather than having to use my own images as pins?

In my application, I have stored coordinates in FireBase and am displaying those coordinates on a Map View in the code below. The current location of the user is also being harnessed. I would like the locations I have stored in FireBase to be represented by the generic Apple Maps pins, but I do not know how to get the app to work unless I use custom images as pins instead. Also, the generic "blue dot" of the user displayed on the map to represent the current location will not appear for me. In different projects in which the locations are stored in-app rather than in FireBase, the generic pins and blue dot appear just as I would like them to. How can I fix this?
I have tried changing bits and pieces of the code, but I am rather new to Swift and the programming world in general, and cannot find a solution.
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBAction func mapSwitch(_ sender: UISwitch) {
if (sender.isOn == true) {
mapView.mapType = MKMapType.standard
}
else {
mapView.mapType = MKMapType.hybrid
}
}
var tappedAnnotation : MKAnnotation?
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let view = mapView.dequeueReusableAnnotationView(withIdentifier: "Annotation") {
view.annotation = annotation
view.image = UIImage(named: "pin")
return view
} else {
let view = MKAnnotationView(annotation: annotation, reuseIdentifier: "Annotation")
view.image = UIImage(named: "pin")
view.isEnabled = true
view.canShowCallout = true
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
return view
}
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
tappedAnnotation = view.annotation
performSegue(withIdentifier: "showAnnotationDetails", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showAnnotationDetails", let dest = segue.destination as? AnnotationDetails {
dest.annotation = tappedAnnotation
}
}
func createAnnotations ( _ annotations : [String:[String:Any]] ) {
mapView.removeAnnotations(mapView.annotations)
for (_,values) in annotations {
if let latDouble = values["latitude"] as? Double, let longDouble = values["longitude"] as? Double {
let lat = CLLocationDegrees( latDouble )
let long = CLLocationDegrees( longDouble )
let coord = CLLocationCoordinate2D(latitude: lat, longitude: long)
let annotation = MKPointAnnotation()
annotation.coordinate = coord
annotation.title = values["name"] as? String ?? ""
annotation.subtitle = values["info"] as? String ?? ""
mapView.addAnnotation(annotation)
}
}
}
let manager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
mapView.delegate = self
mapView.mapType = MKMapType.standard
let ref = Database.database().reference()
ref.child("annotations").observe(.value) { snapshot in
print(snapshot)
if let annotations = snapshot.value as? [String:[String:Any]] {
self.createAnnotations(annotations)
} else {
print("Data received not formatted as expected")
}
}
}
Use MKPinAnnotationView instead of MKAnnotationView
Set mapView.showsUserLocation = true to show user location (blue dot)

Pass the url from the marker into the controller

I'm doing the app for viewing IP cameras and want to add cameras to the map so you can click on the desired marker and go to see the desired camera. I have a map and PlayerViewController which reproduce a webcam.
Now each marker only transmits the first stream of the webcam. Help me. How to make different webcam worked?
ViewController
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var moscow: [(name: String, URLs:String, img:String, latitude: Double, longitude: Double)] =
[("cam1", "http://example/1.m3u8", "1.jpg", 55.753989, 37.620235),
("cam2", "http://example/2.m3u8", "2.jpg", 55.741308, 37.653914),
("cam3","http://example/3.m3u8","3.jpg", 55.742468, 37.629292)]
override func viewDidLoad() {
super.viewDidLoad()
var latitudes = moscow.map({ $0.latitude })
var longitudes = moscow.map({ $0.longitude })
var annotations = moscow.map({ $0.name })
for i in 0...2 {
let coordinate = CLLocationCoordinate2DMake(latitudes[i], longitudes[i])
let span = MKCoordinateSpanMake(0.003, 0.003)
let region = MKCoordinateRegionMake(coordinate, span)
mapView.setRegion(region, animated:true)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = annotations[i]
self.mapView.addAnnotation(annotation)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
print(#function)
}
// Called when the annotation was added
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.animatesDrop = true
pinView?.canShowCallout = true
pinView?.isDraggable = true
pinView?.pinColor = .purple
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
} else {
pinView?.annotation = annotation
}
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
print(#function)
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "toTheMoon", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toTheMoon" {
let controller = segue.destination as! PlayerViewController
var urlll = moscow.map({ $0.URLs })
for i in 0...2 {
controller.webcamURL = urlll[i] // only first cam play
}
}
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.ending {
let droppedAt = view.annotation?.coordinate
print(droppedAt)
}
}
}
PlayerViewController
import UIKit
import AVFoundation
import AVKit
class PlayerViewController: AVPlayerViewController {
var webcamURL: String!
var webcamTitle: String!
override func viewDidLoad() {
super.viewDidLoad()
self.title = webcamTitle
let url = URL(string: webcamURL)
player = AVPlayer(url: url!)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
player!.play()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.player!.pause()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
player = nil
}
}
First of All MKAnnotation is a Protocol so you can implement this protocol in your model class, lets say "Camera"
import UIKit
import MapKit
class Camera: NSObject, MKAnnotation {
var name: String = ""
var urlString :String = ""
var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 0, longitude: 0)
var imageName : String = ""
init(name:String,camUrl:String,imageNamed:String,latitude:CLLocationDegrees,longitude:CLLocationDegrees) {
super.init()
self.name = name
self.urlString = camUrl
self.imageName = imageNamed
guard latitude != 0 && longitude != 0 else
{
return
}
guard latitude.isNaN || longitude.isNaN else
{
return
}
self.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
// Title and subtitle for use by selection UI.
public var title: String? {
get{
return self.name
}
}
}
Then you can reduce your ViewController code like this
import UIKit
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
var moscow: [Camera] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.moscow = [Camera(name: "cam1", camUrl: "http://example/1.m3u8", imageNamed: "1.jpg", latitude: 55.753989, longitude: 37.620235),
Camera(name: "cam2", camUrl: "http://example/2.m3u8", imageNamed: "2.jpg", latitude: 55.741308, longitude: 37.653914),
Camera(name: "cam3", camUrl: "http://example/3.m3u8", imageNamed: "3.jpg", latitude: 55.742468, longitude: 37.629292)]
self.mapView.addAnnotations(self.moscow)
self.mapView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController : MKMapViewDelegate
{
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
print(#function)
}
// Called when the annotation was added
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.animatesDrop = true
pinView?.canShowCallout = true
pinView?.isDraggable = true
pinView?.pinColor = .purple
let rightButton: AnyObject! = UIButton(type: UIButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
} else {
pinView?.annotation = annotation
}
return pinView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
print(#function)
let camera = view.annotation as! Camera
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "toTheMoon", sender: camera)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toTheMoon" {
let controller = segue.destination as! PlayerViewController
controller.webcamURL = (sender as! Camera).urlString
controller.webcamTitle = (sender as! Camera).name
}
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.ending {
let droppedAt = view.annotation?.coordinate
print(droppedAt)
}
}
}
Hope this helps

ViewForAnnotation not Called in Swift 3

I want to open a new viewcontroller when i click the PinAnnotation. But ViewForannotation is not calling when i click, But It is showing a pop up message when i click on Pin. Don't know what is happening. Here is my Code:
import UIKit
import MapKit
class Pin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var key: String
var title: String?
var age: String?
var category: String?
var color: MKPinAnnotationColor = MKPinAnnotationColor.purple
var subtitle: String?
init(key: String, name: String , age: String , category: String , color: MKPinAnnotationColor) {
self.coordinate = CLLocationCoordinate2D(latitude: 0, longitude: 0)
self.key = key
self.title = name
self.color = color
self.subtitle = age
self.category = category
//print("keyy: ", key)
//print("title: ", name)
}
}
This is my MapViewControllerClass:
import UIKit
import GeoFire
import MapKit
import Firebase
import CoreLocation
class MapViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate, UIAlertViewDelegate {
//#IBOutlet weak var sidebarButton: UIBarButtonItem!
#IBOutlet weak var mapView: MKMapView!
//#IBOutlet weak var chatbarButton: UIBarButtonItem!
/* ---> NEW MAP-IT <--- */
let locationManager = CLLocationManager()
let imagePicker = UIImagePickerController()
var regionQuery: GFRegionQuery?
var foundQuery: GFCircleQuery?
var annotations: Dictionary<String, Pin> = Dictionary(minimumCapacity: 8)
var lastExchangeKeyFound: String?
var lastExchangeLocationFound: CLLocation?
var location: CLLocation!
// var location = CLLocation(latitude: 37.33233141, longitude: -122.0312186)
//let location = CLLocation(latitude: 37.33209999, longitude: -122.0326666)
var circle: MKCircle!
var index = 0
var val1Lat: Double!
var val2Lat: Double!
var val1Long: Double!
var val2Long: Double!
var flag = false
var userName = ""
var age = ""
var category = ""
var uid = ""
override func viewDidLoad() {
super.viewDidLoad()
uid = DataService.ds.currentUserID
self.mapView.delegate = self
// locationManager.requestAlwaysAuthorization()
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) || (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) {
print("Authorized")
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
} else {
print("Application is not authorized to use location services")
//- TODO: Unauthorized, requests permissions again and makes recursive call
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if manager.location?.coordinate != nil {
if flag == true {
if (location.coordinate.latitude != manager.location?.coordinate.latitude) || (location.coordinate.longitude != manager.location?.coordinate.longitude) {
location = manager.location!//.coordinate
print("lat: \(location.coordinate.latitude)")
print("long: \(location.coordinate.longitude)")
animateMap(location: location)
let key = DataService.ds.currentUserID
geofire!.setLocation(location, forKey: key)
}
} else {
print("Else:LocationManag")
location = manager.location!
print("lat: \(location.coordinate.latitude)")
print("long: \(location.coordinate.longitude)")
animateMap(location: location)
flag = true
let key = DataService.ds.currentUserID
geofire!.setLocation(location, forKey: key)
}
}
}
override func viewDidAppear(_ animated: Bool) {
print("DidAppear")
self.mapView.userLocation.addObserver(self, forKeyPath: "location", options: NSKeyValueObservingOptions(), context: nil)
}
override func viewDidDisappear(_ animated: Bool) {
print("DidDisAppear")
locationManager.stopUpdatingLocation()
self.mapView.userLocation.removeObserver(self, forKeyPath: "location", context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("In observer")
if (self.mapView.showsUserLocation) && (self.mapView.userLocation.location) != nil
{
let span = MKCoordinateSpanMake(0.0125, 0.0125)
let region = MKCoordinateRegion(center: self.mapView.userLocation.location!.coordinate /*location.coordinate*/, span: span)
self.mapView.setRegion(region, animated: true)
if foundQuery == nil {
print("FoundQuery nill")
foundQuery = geofire?.query(at: /*location*/self.mapView.userLocation.location, withRadius: 0.2)
foundQuery!.observe(GFEventType.keyEntered, with: { (key: String?, location:CLLocation?) -> Void in
//print("here")
DataService.ds.userRef.child(key!).observeSingleEvent(of: .value, with: { (snapshot) in
if let userDictionary = snapshot.value as? Dictionary<String , AnyObject>
{
self.userName = userDictionary["firstName"] as! String
self.age = userDictionary["age"] as! String
self.category = userDictionary["category"] as! String
}
self.lastExchangeKeyFound = key
self.lastExchangeLocationFound = location
if key != DataService.ds.currentUserID {
let annotation = Pin(key: key!, name: self.userName , age: self.age , category: self.category , color: MKPinAnnotationColor.green)
annotation.coordinate = (location?.coordinate)!
annotation.title = self.userName + " - " + self.age
annotation.subtitle = self.category
// if self.category == "Trainer"{
// annotation.color = MKPinAnnotationColor.green
// }else{
// annotation.color = MKPinAnnotationColor.purple
// }
self.mapView.addAnnotation(annotation)
self.annotations[key!] = annotation
}
})
self.foundQuery?.observe(.keyExited, with: { (key, location) in
if key != DataService.ds.currentUserID {
if self.annotations[key!] != nil {
self.mapView.removeAnnotation(self.annotations[key!]!)
self.annotations[key!] = nil
}
}
})
})
}
else
{
foundQuery?.center = self.mapView.userLocation.location
}
}
}
//Click Event For Annotation:
// func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!,
// calloutAccessoryControlTapped control: UIControl!) {
//
// if control == view.rightCalloutAccessoryView {
// print("Disclosure Pressed! \(view.annotation?.subtitle)")
// }
//
// }
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
print("inPin1")
if annotation is Pin {
print("inPin2")
let pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "myPin")
pinAnnotationView.pinColor = .purple
pinAnnotationView.isDraggable = true
pinAnnotationView.canShowCallout = true
pinAnnotationView.animatesDrop = true
let deleteButton = UIButton.init(type: UIButtonType.custom) as UIButton
// let deleteButton = UIButton.withType(UIButtonType.custom) as UIButton
deleteButton.frame.size.width = 44
deleteButton.frame.size.height = 44
deleteButton.backgroundColor = UIColor.red
deleteButton.setImage(UIImage(named: "xbutton"), for: .normal)
pinAnnotationView.leftCalloutAccessoryView = deleteButton
return pinAnnotationView
}
return nil
}
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
if let annotation = view.annotation as? Pin {
mapView.removeAnnotation(annotation)
}
}
// func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView {
// var annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "loc")
// annotationView.canShowCallout = true
// annotationView.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
// return annotationView
// }
//
// func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
// mapView.deselectAnnotation(view.annotation, animated: true)
// var controller = self.storyboard!.instantiateViewController(withIdentifier: "DetailsPopover")
// controller.annotation! = view.annotation
// self.popover = UIPopoverController(contentViewController: controller)
// self.popover.delegate = self
// self.popover.presentPopoverFromRect(view.frame, inView: view.superview!, permittedArrowDirections: .Any, animated: true)
// }
// func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
// print("helloooo")
// self.performSegue(withIdentifier: "detailView", sender: view)
// }
// func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// // simple and inefficient example
// let annotationView = MKPinAnnotationView()
// if category == "Trainer"{
// annotationView.pinTintColor = .purple
// }else{
// annotationView.pinTintColor = .green
// }
//
//
//
// return annotationView
// }
func animateMap(location: CLLocation)
{
// print("animate Map")
let region = MKCoordinateRegionMakeWithDistance(location.coordinate, 1000, 1000)
mapView.setRegion(region, animated: true)
addRadiusCircle(location: location)
}
func addRadiusCircle(location: CLLocation)
{
//print("Add Radius")
//self.mapView.delegate = self
if circle != nil
{
self.mapView.remove(circle)
}
circle = MKCircle(center: location.coordinate, radius: 200 as CLLocationDistance)
self.mapView.add(circle)
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
{
if overlay is MKCircle
{
let circle = MKCircleRenderer(overlay: overlay)
circle.strokeColor = UIColor.red
circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
circle.lineWidth = 1
return circle
}
else {
let temp = MKOverlayRenderer()
return temp
}
}
}
I am Using Geofire to get the nearby users in a particular radius and then pin that users. Please help.
You are saying:
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!
That will certainly never be called. In Swift 3, the correct signature is:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
All you have to do is consult the documentation:
https://developer.apple.com/reference/mapkit/mkmapviewdelegate/1452045-mapview
In case anyone else was having the same issue while still using the correct signature, ensure you've set your mapView delegate:
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}

Opening MapKit pin in Maps

I can't seem to get the final part of Ray Wenderlich's mapkit tutorial to work. I get the pins to display correctly but when I click on the pin, it doesn't open in Maps as I would like it too. Here is the link to the full tutorial (Link)
And here is my code:
import Foundation
import UIKit
import MapKit
import AddressBook
class CroquisMapView: UIViewController, MKMapViewDelegate {
var section : Int?
var index : Int?
#IBOutlet weak var mapView: MKMapView!
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
override func viewDidLoad() {
mapView.delegate = self
let coordenadas = croquisGruposArray[section!].items[index!].coordenadas
let coordenadasArray = coordenadas!.characters.split{$0 == ","}.map(String.init)
guard let lat = NSNumberFormatter().numberFromString(coordenadasArray[0])?.doubleValue,
let long = NSNumberFormatter().numberFromString(coordenadasArray[1])?.doubleValue else {
return
}
let initialLocation = CLLocation(latitude: lat, longitude: long)
let artwork = Artwork(title: "\(croquisGruposArray[section!].items[index!].descripcion!)",
locationName: "\(globalLigaNombre!)",
discipline: "Futbol",
coordinate: CLLocationCoordinate2D(latitude: lat, longitude: long))
mapView.addAnnotation(artwork)
centerMapOnLocation(initialLocation)
}
}
class Artwork: NSObject, MKAnnotation {
let title: String?
let locationName: String
let discipline: String
let coordinate: CLLocationCoordinate2D
init(title: String, locationName: String, discipline: String, coordinate: CLLocationCoordinate2D) {
self.title = title
self.locationName = locationName
self.discipline = discipline
self.coordinate = coordinate
super.init()
}
var subtitle: String? {
return locationName
}
func mapItem() -> MKMapItem {
let addressDictionary = [String(kABPersonAddressStreetKey): locationName]
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: addressDictionary)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = title
return mapItem
}
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
print("CLICKED")
let location = view.annotation as! Artwork
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
location.mapItem().openInMapsWithLaunchOptions(launchOptions)
}
}
extension CroquisMapView {
// 1
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? Artwork {
let identifier = "pin"
var view: MKPinAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
as? MKPinAnnotationView { // 2
dequeuedView.annotation = annotation
view = dequeuedView
} else {
// 3
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure) as UIView
}
return view
}
return nil
}
}
Figured it out: I wasn't calling calloutAccessoryControlTapped in my main class. I added it and it with the code provided by Andrej:
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let url = NSURL(string: "http://maps.apple.com/?q=\(lat),\(long)")
if UIApplication.sharedApplication().canOpenURL(url!) == true {
UIApplication.sharedApplication().openURL(url!)
}
}
You can try this:
let url = NSURL(string: "http://maps.apple.com/?q=44.33833,13.98131")
if UIApplication.sharedApplication().canOpenURL(url!) == true
{
UIApplication.sharedApplication().openURL(url!)
}
You can also do like this:
extension ViewController : MKMapViewDelegate {
func getDirections(){ // Here you can put everything, this function is calling when the user select the dialogue pin's bubble. I propose a code who open the application Map.
guard let selectedPin = selectedPin else { return }
let mapItem = MKMapItem(placemark: selectedPin)
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
mapItem.openInMapsWithLaunchOptions(launchOptions)
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?{
guard !(annotation is MKUserLocation) else { return nil }
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
}
pinView?.pinTintColor = UIColor.orangeColor()
pinView?.canShowCallout = true
let smallSquare = CGSize(width: 30, height: 30)
let button = UIButton(frame: CGRect(origin: CGPointZero, size: smallSquare))
button.setBackgroundImage(UIImage(named: "car"), forState: .Normal)
button.addTarget(self, action: #selector(self.getDirections), forControlEvents: .TouchUpInside)
pinView?.leftCalloutAccessoryView = button
return pinView}
}