My button I created progmatically to push from my app the Apple Maps app stopped working.. why? - ios

I have a navigation app I am working on which works like a normal maps app, allowing you to search for locations through a search table etc. So in my app I have a button which allows for the user to add multiple annotations (be default every time the user clicks a new result in the searchtable I have it set to remove the most recent annotation) and find the centerpoint between all these areas. The code then shifts that centerpoint to the closest address so there is a place to get directions to, not just lat and long. Anyway, I have it set so that when the user taps the annotation, a button appears right above it, and the button is supposed to send you to apple maps with the preset route already loaded in. This worked until recently. Here is the code that carries this button's actions out:
extension ViewController : MKMapViewDelegate {
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()), size: smallSquare))
button.setBackgroundImage(UIImage(named: "car"), for: [])
button.addTarget(self, action: #selector(getDirections), for: UIControlEvents.touchUpInside)
pinView?.leftCalloutAccessoryView = button
return pinView
}
}
and in the class
#objc func getDirections(){
if let selectedPin = selectedPin {
let mapItem = MKMapItem(placemark: selectedPin)
let launchOptions = [MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving]
mapItem.openInMaps(launchOptions: launchOptions)
}
}
Could it be something weird with the objective C function? This is the code I recently added that potentially could have caused the issue, though I really don't know:
func resolveAddress(for averageCoordinate: CLLocationCoordinate2D, completion: #escaping (MKPlacemark?) -> () ) {
let geocoder = CLGeocoder()
let averageLocation = CLLocation(latitude: averageCoordinate.latitude, longitude: averageCoordinate.longitude)
geocoder.reverseGeocodeLocation(averageLocation) { (placemarks, error) in
guard error == nil,
let placemark = placemarks?.first
else {
completion(nil)
return
}
completion(MKPlacemark(placemark: placemark ))
}
}
#IBAction func middleFinderButton(_ sender: Any) {
let totalLatitude = mapView.annotations.reduce(0) { $0 + $1.coordinate.latitude }
let totalLongitude = mapView.annotations.reduce(0) { $0 + $1.coordinate.longitude }
let averageLatitude = totalLatitude/Double(mapView.annotations.count)
let averageLongitude = totalLongitude/Double(mapView.annotations.count)
let centerPoint = MKPointAnnotation()
centerPoint.coordinate.latitude = averageLatitude
centerPoint.coordinate.longitude = averageLongitude
mapView.addAnnotation(centerPoint)
resolveAddress(for: centerPoint.coordinate) { placemark in
if let placemark = placemark {
self.mapView.addAnnotation(placemark)
} else {
self.mapView.addAnnotation(centerPoint)
}
}
print(totalLatitude)
print(totalLongitude)
print(averageLatitude)
print(averageLongitude)
print(centerPoint.coordinate)
}
}
Anyone have an idea why this button isn't working and pushing the app to maps with a preset route? could it be a glitch with the simulator(it used to work so I doubt it)? Thanks.

Related

How to turn a MKPointAnnotation to a button?

Whenever a user taps on an MKPointAnnotation, I want him to be redirected to a specific view. My problem is how do I get the annotation to perform an action when tapped?
Here is my code:
for i in closestpharmacyname {
var docref2 = db.collection("pharmacies").document(i)
print("Pharmacy: ", i)
docref2.getDocument(source: .cache) { (document, error) in
if var document = document {
var pharmacylatitude = document.get("latitude") as! Double
var pharmacylongitude = document.get("longitude") as! Double
print(pharmacylatitude, pharmacylongitude)
var pharmacyannotation = MKPointAnnotation()
pharmacyannotation.coordinate = CLLocationCoordinate2D(latitude: pharmacylatitude, longitude: pharmacylongitude)
pharmacyannotation.title = i
self.MapView.addAnnotation(pharmacyannotation)
} else{
print("Document Does not exist")
}
}
}
To do this, you need to add:
yourAnnotationView?.rightCalloutView = UIButton(type: UIButtonType.detailDisclosure)
into your mapView(_:viewFor:) function. This will change the looks of your annotation, but there will be a button on the side that you can press to do different tasks.The annotation will look something like this:
In order to handle these tasks, you also need to add a new function:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
//perform tasks here
}

Offline map tiles have stopped displaying

I have downloaded tiles for a small town in zooms 15 to 18. They were displaying as expected but now don't.
I was using xcode 7 with swift 2 on Yosemite. I'm now with xcode 8.1 with swift 3 on sierra. I'm pretty sure the problem started before the upgrade, but have no time machine to go back. I upgraded because I wanted to test the app on my IPad 2, got the message that xcode wasn't compatible with the ios on the ipad, then got a message that xcode 8.1 cant be loaded to Yosemite hence upgrade to sierra.
The code is below. And the console output bellow that. No error given
//
// MapViewController.swift
// button scale
//
// Created by Colin McGarry on 24/03/16.
// Copyright © 2016 Colin McGarry. All rights reserved.
//
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController /*, MKMapViewDelegate*/{
var guideData: GuideData?
var dataM:[GuideData] = [GuideData]()
var placeNumb = 0
var modifyingMap = true
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let IS_RETINA = (UIScreen.mainScreen().respondsToSelector(#selector(UIScreen.displayLinkWithTarget(_:selector:))) && (UIScreen.mainScreen().scale >= 2.0))
// from shankar map
if IS_RETINA {
print("Is Retina")
} else {
print("not retina")
}
zoomToRegion()
let annotations = getMapAnnotations()
// Add mappoints to Map
mapView.addAnnotations(annotations)
// end shankar map
//Get the URL template to the map tiles
let baseURL = NSBundle.mainBundle().bundleURL.absoluteString
let urlTemplate = baseURL!.stringByAppendingString("osmm/{z}/{x}/{y}.png/")
//let urlTemplate = baseURL.stringByAppendingString("two/{z}/{x}/{y}#2x.png/")
//let urlTemplate = "http://tile.openstreetmap.org/{z}/{x}/{y}.png"
print(urlTemplate)
let carte_indice = MKTileOverlay(URLTemplate:urlTemplate)
carte_indice.geometryFlipped = false
carte_indice.canReplaceMapContent = true
//carte_indice.tileSize = CGSize(width: 512, height: 512)
carte_indice.maximumZ = 16
carte_indice.minimumZ = 18
self.mapView.addOverlay(carte_indice)
}
/// from shankar map
func zoomToRegion() {
let location = CLLocationCoordinate2D(latitude: 49.275, longitude: -0.7028)
let region = MKCoordinateRegionMakeWithDistance(location, 500.0, 500.0)
mapView.setRegion(region, animated: true)
}
//MARK:- Annotations
func getMapAnnotations() -> [Stands] {
var annotations:Array = [Stands]()
//load plist file
var stands: NSArray?
if let path = NSBundle.mainBundle().pathForResource("stands", ofType: "plist") {
stands = NSArray(contentsOfFile: path)
}
//iterate and create annotations
if let items = stands {
for item in items {
let lat = item.valueForKey("lat") as! Double
let long = item.valueForKey("long")as! Double
let annotation = Stands(latitude: lat, longitude: long)
let tit = item.valueForKey("title") as! String
let numb = item.valueForKey("no") as! Int
annotation.title = "\(numb) \(tit)"
annotation.no = numb
// new added
// annotation.enabled = true
// annotation.canShowCallOut = true
// end added
annotations.append(annotation)
}
}
return annotations
}
// end From Shankar map
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
// 1
let identifier = "Stand"
// 2
if annotation.isKindOfClass(Stands.self) {
// 3
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if annotationView == nil {
//4
annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:identifier)
annotationView!.canShowCallout = true
// 5
let btn = UIButton(type: .DetailDisclosure)
annotationView!.rightCalloutAccessoryView = btn
} else {
// 6
annotationView!.annotation = annotation
}
return annotationView
}
// 7
return nil
}
func mapView( mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
let standM = view.annotation as! Stands
let placeName = standM.title
let placeInfo = standM.title
placeNumb = standM.no!
/*
let ac = UIAlertController(title: placeName, message: placeInfo, preferredStyle: .Alert)
ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(ac, animated: true, completion: nil) */
performSegueWithIdentifier("MapToText", sender: self)
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
// enforce maximum zoom level
let place = mapView.visibleMapRect
if( place.origin.x < 133686298
|| place.origin.x > 133697376
|| place.origin.y < 91864219
|| place.origin.y > 91874305
)
{
zoomToRegion()
}
print("alt \(mapView.camera.altitude)")
let maxAlt = 3000.00
if (mapView.camera.altitude > maxAlt && self.modifyingMap)
{
self.modifyingMap = false
// prevents strange infinite loop case
self.mapView.zoomEnabled = false
/* self.mapView.scrollEnabled = false
self.mapView.userInteractionEnabled = false
*/
print("place \(place)")
self.mapView.camera.altitude = maxAlt
self.modifyingMap = true
print("alt>\(maxAlt)")
} else {
self.mapView.zoomEnabled = true
print("place2 \(place)")
print("x \(place.origin.x)")
print(" alt less than \(maxAlt)")
print(mapView.camera.altitude)
}
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer!
{
print("call overlay")
if overlay is MKTileOverlay
{
print("is MKTileoverlay")
let renderer = MKTileOverlayRenderer(overlay:overlay)
renderer.alpha = 0.8
return renderer
}
return nil
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "MapToText" {
let webviewController:webViewController = segue.destinationViewController as! webViewController
webviewController.index = placeNumb - 1
// webviewController.standTitle = sender as! MKAnnotationView
webviewController.inde = placeNumb - 1
print("prepSeg \(webviewController.inde)")
}
}
}
console output
/Users/colinmcgarry/Library/Developer/CoreSimulator/Devices/4F5E35FC-45F9-4A16-8A0A-1AFD51616CCA/data/Containers/Bundle/Application/046B53E5-D3CD-4E7A-926D-7D77E069AAA0/button scale.app/stands.plist
Optional("/Users/colinmcgarry/Library/Developer/CoreSimulator/Devices/4F5E35FC-45F9-4A16-8A0A-1AFD51616CCA/data/Containers/Bundle/Application/046B53E5-D3CD-4E7A-926D-7D77E069AAA0/button scale.app/2page.html")
Is Retina
alt 1100.94691259802
place2 MKMapRect(origin: __C.MKMapPoint(x: 133691120.58898854, y: 91870217.34526816), size: __C.MKMapSize(width: 5123.4971518665552, height: 6063.3100336045027))
x 133691120.588989
alt less than 3000.0
1100.94691259802
file:///Users/colinmcgarry/Library/Developer/CoreSimulator/Devices/4F5E35FC-45F9-4A16-8A0A-1AFD51616CCA/data/Containers/Bundle/Application/046B53E5-D3CD-4E7A-926D-7D77E069AAA0/button%20scale.app/osmm/{z}/{x}/{y}.png/
call overlay
is MKTileoverlay
I found the problem. But it's not in the code I included.
I had put min and max zoom. When I changed the values I interchanged min and max
overlay.maximumZ = 15
overlay.minimumZ = 17
These conditions are mutually contradicting so overlay didn't show.
if I'd written min above max I might have noticed before.

Pin correct Annotation Image parse backend

I have setup a map in which data is loaded from the parse backend. In map I want to display the images that are already saved in Assets folder. Image should be equal to Player Name . There latitude and longitude is already saved in the Parse.
The position of the player is displayed correctly but the image is not being showed correctly , if the last name in the playerName column is Sachin then the image is same for all the player annotation pin.
I want to apply like if playerName == annotation.title the image of rahul should be displayed .
Console Print :
26.6481591686873 , 77.1777485870544 Sachin
27.655116868732 , 77.17778705437 Rahul
28.6479996556687 , 77.1779252453013 Matt
28.6480628887157 , 77.1779590059193 Virat
28.1578689896 , 76.989079 Sachin
var playerName:String!
override func viewDidLoad() {
super.viewDidLoad()
query.findObjectsInBackgroundWithBlock { (posts, error) in
if error == nil {
let myPosts = posts! as [PFObject]
for posts in myPosts {
let latitude12 = posts["playerLat"] as! Double
let longitude12 = posts["playerLong"] as! Double
let playName = posts["playerName"] as! String
self.playerName = posts["playerName"] as! String
print(latitude12,"," , longitude12, playerName)
let annotation = MKPointAnnotation()
//let customAnno = MKAnnotationView()
let locationCoordinate = CLLocationCoordinate2DMake(latitude12, longitude12)
annotation.coordinate = locationCoordinate
//customAnno.enabled = true
let anno = self.mapView.dequeueReusableAnnotationViewWithIdentifier("places")
if anno == nil {
// if annotation.title == "Sachin" {
//}
annotation.title = playerName
self.mapView.addAnnotations([annotation])
} else {
anno?.annotation = annotation
}
}
}
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "customAnnotationView"
let annotation1 = MKPointAnnotation()
// custom image annotation
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if (annotationView == nil) {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
}
else {
annotationView!.annotation = annotation
}
if annotation1.title == "Rahul" {
annotationView!.image = UIImage(named: "Rahul")}
else if annotation1.title == "Sachin"{
annotationView!.image = UIImage(named: "Sachin")
}
return annotationView
}
I have tried all codes but the image is same for all the players image.

Associating different pin images with different locations iOS

I have an array of 4 locations, and an array of 4 pin names (ie "bluePin.png | redPin.png | etc...")
Currently I'm using a bit of code I found elsewhere to add custom pin graphics to all 4 locations, but all of my pins are red.
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
let annotationReuseId = "Truck"
var trkPin = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationReuseId)
if trkPin == nil {
trkPin = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationReuseId)
} else {
trkPin!.annotation = annotation
}
trkPin!.image = UIImage(named: "redPin.png")
trkPin!.backgroundColor = UIColor.clearColor()
trkPin!.canShowCallout = false
return trkPin
}
How could I associate the pin colors with the locations in the array, so that each location is differentiated by color?
Thanks!
I have done this in the simple way by declaring array of location and array images. And I have viewDidLoad method as follows.
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
let location = [
CLLocationCoordinate2D(latitude: 12, longitude: 77),
CLLocationCoordinate2D(latitude: 12.5, longitude: 77.5),
CLLocationCoordinate2D(latitude: 13, longitude: 78),
CLLocationCoordinate2D(latitude: 13.5, longitude: 78)
]
let pins = [
"red.png",
"blue.png",
"green.png",
"yellow.png"
]
var annotations = [MKPointAnnotation]()
for (index, eachLocation) in location.enumerate() {
let pinImageName = pins[index]
let annotation = MKPointAnnotation()
annotation.coordinate = eachLocation
annotation.title = "\(pinImageName)"
annotations.append(annotation)
}
mapView.addAnnotations(annotations)
}
And in the viewForAnnotation delegate method just getting that image name from the title property and explicitly disabling the callout
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let annotationReuseId = "Truck"
var trkPin = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationReuseId)
if trkPin == nil {
trkPin = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationReuseId)
trkPin!.canShowCallout = false
} else {
trkPin!.annotation = annotation
if let image = annotation.title {
trkPin!.image = UIImage(named: image ?? "default.png")
} else {
trkPin!.image = UIImage(named: "default.png")
}
}
return trkPin
}

Attempting to change MKAnnotation color within my code?

So I have set up my MKAnnotations in MapView and it's working as I want it to. Now I would like to experiment further and try to change the colors of the pins, what would be the most efficient way to implement this within the following code:
override func viewDidAppear(animated: Bool) {
var annotationQuery = PFQuery(className: "Post")
currentLoc = PFGeoPoint(location: MapViewLocationManager.location)
//annotationQuery.whereKey("Location", nearGeoPoint: currentLoc, withinMiles: 10)
annotationQuery.whereKeyExists("Location")
annotationQuery.findObjectsInBackgroundWithBlock {
(points, error) -> Void in
if error == nil {
// The find succeeded.
println("Successful query for annotations")
// Do something with the found objects
let myPosts = points as! [PFObject]
for post in myPosts {
let point = post["Location"] as! PFGeoPoint
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(point.latitude, point.longitude)
annotation.title = post["title"] as! String!
annotation.subtitle = post["username"] as! String!
func mapView(aMapView: MKMapView!,
viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
let reuseId = "pin"
var pinView = aMapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.pinColor = .Green
return pinView
}
self.mapView.addAnnotation(annotation)
}
} else {
// Log details of the failure
println("Error: \(error)")
}
}
I can't seem to tackle this on my own even though it seem's simple enough. I am also confused about the viewForAnnotation method, from what I could gather it seems like i need to use it, but nothing i'm trying is working.
I know this is a late answer but for anyone else searching, check out the tutorial here which shows exactly how to colour pins
Ray Wenderlich MapView

Resources