Remove annotations from map and replace with updated annotations (qTree) - ios

I am currently working on adding cluster annotations to my map view. Everything is working fine with the exception of a couple of things. First of all, I need to refresh the annotations on the map when the user leaves and returns to the view. At the moment this sort of works... The problem is that rather than removing the annotations and adding the new ones, the new ones are just being added in addition of the old ones so there are multiplying each time.
The next issue is that each annotation displays the distance the user is from that annotation, however the annotations are set up before the user's location is found. I assume I will just have to remove and replace the annotations once the location is found, but then I run into the issue of the annotations duplicating again.
This is my code:
override func viewDidAppear(animated: Bool) {
println(rideArray.count)
setUpMapView()
}
func setUpMapView() {
rideArray = ((DataManager.sharedInstance.rideArray) as NSArray) as! [Ride]
myLocation = mapView.userLocation.coordinate as CLLocationCoordinate2D
zoomRegion = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2D(latitude: parkPassed.latitude!, longitude: parkPassed.longitude!), 1000, 1000)
mapView.setRegion(zoomRegion, animated: true)
mapView.delegate = self
for ride in rideArray {
println("Location: \(mapView.userLocation.coordinate.latitude)")
var subtitle = ""
if mapView.userLocation.location == nil {
subtitle = "Distance unavailable"
} else {
let userLocation = CLLocation(latitude: mapView.userLocation.coordinate.latitude, longitude: mapView.userLocation.coordinate.longitude)
let annotationLocation = CLLocation(latitude: ride.latitude!, longitude: ride.longitude!)
var distance = Int(CLLocationDistance(annotationLocation.distanceFromLocation(userLocation)))
if distance > 1000 {
distance = distance / 1000
subtitle = "\(distance) kilometers"
} else {
subtitle = "\(distance) meters"
}
}
let annotation = RideAnnotation(coordinate: CLLocationCoordinate2DMake(ride.latitude!, ride.longitude!), title: ride.name!, subtitle: subtitle)
self.qTree.insertObject(annotation)
}
var leftSwipe = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:"))
var rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:"))
leftSwipe.direction = .Left
rightSwipe.direction = .Right
view.addGestureRecognizer(leftSwipe)
view.addGestureRecognizer(rightSwipe)
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation.isKindOfClass(QCluster.classForCoder()) {
let PinIdentifier = "PinIdentifier"
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(ClusterAnnotationView.reuseId()) as? ClusterAnnotationView
if annotationView == nil {
annotationView = ClusterAnnotationView(cluster: annotation)
}
annotationView!.cluster = annotation
return annotationView
} else if annotation.isKindOfClass(RideAnnotation.classForCoder()) {
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier("RideAnnotation")
if pinView == nil {
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: "RideAnnotation")
pinView?.canShowCallout = true
pinView?.rightCalloutAccessoryView = UIButton.buttonWithType(UIButtonType.DetailDisclosure) as! UIButton
pinView?.rightCalloutAccessoryView.tintColor = UIColorFromRGB(0x424242)
let rideTimeView = UIView()
rideTimeView.frame = CGRectMake(5, 5, 50, 50)
rideTimeView.layer.cornerRadius = 25
let waitTimeLabel = UILabel()
waitTimeLabel.frame = CGRectMake(0, 0, 50, 50)
if DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime! == "Closed" {
waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)"
rideTimeView.backgroundColor = getColorFromNumber(80)
waitTimeLabel.font = UIFont(name: "Avenir", size: 15)
} else {
waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)m"
rideTimeView.backgroundColor = getColorFromNumber(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!.toInt()!)
waitTimeLabel.font = UIFont(name: "Avenir", size: 20)
}
waitTimeLabel.textAlignment = NSTextAlignment.Center
waitTimeLabel.textColor = UIColor.whiteColor()
waitTimeLabel.adjustsFontSizeToFitWidth = true
waitTimeLabel.numberOfLines = 1
rideTimeView.addSubview(waitTimeLabel)
pinView.leftCalloutAccessoryView = rideTimeView
pinView?.image = UIImage(named: "rideMapAnnotation")
} else {
pinView?.annotation = annotation
let rideTimeView = UIView()
rideTimeView.frame = CGRectMake(5, 5, 50, 50)
rideTimeView.layer.cornerRadius = 25
let waitTimeLabel = UILabel()
waitTimeLabel.frame = CGRectMake(0, 0, 50, 50)
if DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime! == "Closed" {
waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)"
rideTimeView.backgroundColor = getColorFromNumber(80)
waitTimeLabel.font = UIFont(name: "Avenir", size: 15)
} else {
waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)m"
rideTimeView.backgroundColor = getColorFromNumber(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!.toInt()!)
waitTimeLabel.font = UIFont(name: "Avenir", size: 20)
}
waitTimeLabel.textAlignment = NSTextAlignment.Center
waitTimeLabel.textColor = UIColor.whiteColor()
waitTimeLabel.adjustsFontSizeToFitWidth = true
waitTimeLabel.numberOfLines = 1
rideTimeView.addSubview(waitTimeLabel)
pinView.leftCalloutAccessoryView = rideTimeView
}
return pinView
}
return nil
}
func reloadAnnotations(){
if self.isViewLoaded() == false {
return
}
self.cacheArray.removeAll(keepCapacity: false)
let mapRegion = self.mapView.region
let minNonClusteredSpan = min(mapRegion.span.latitudeDelta, mapRegion.span.longitudeDelta) / 5
let objects = self.qTree.getObjectsInRegion(mapRegion, minNonClusteredSpan: minNonClusteredSpan) as NSArray
for object in objects {
if object.isKindOfClass(QCluster){
let c = object as? QCluster
let neighbours = self.qTree.neighboursForLocation((c?.coordinate)!, limitCount: NSInteger((c?.objectsCount)!)) as NSArray
for neighbour in neighbours {
let tmp = self.rideArray.filter({
return $0.name == (neighbour.title)!!
})
if find(self.cacheArray, tmp[0]) == nil {
self.cacheArray.insert(tmp[0], atIndex: self.cacheArray.count)
}
}
} else {
let tmp = self.rideArray.filter({
return $0.name == (object.title)!!
})
if find(self.cacheArray, tmp[0]) == nil {
self.cacheArray.insert(tmp[0], atIndex: self.cacheArray.count)
}
}
}
let annotationsToRemove = (self.mapView.annotations as NSArray).mutableCopy() as! NSMutableArray
annotationsToRemove.removeObject(self.mapView.userLocation)
annotationsToRemove.removeObjectsInArray(objects as [AnyObject])
self.mapView.removeAnnotations(annotationsToRemove as [AnyObject])
let annotationsToAdd = objects.mutableCopy() as! NSMutableArray
annotationsToAdd.removeObjectsInArray(self.mapView.annotations)
self.mapView.addAnnotations(annotationsToAdd as [AnyObject])
}
func mapView(mapView: MKMapView!, regionDidChangeAnimated animated: Bool) {
viewChanged = true
self.reloadAnnotations()
}
I apologise for the extensive amount of code, but it all had to be included.
Anyone have any suggestions as to how I can remove the annotations and re-add them once the view appears?
Thanks!
EDIT:
The second issue is now resolved. Here is a bit more detail in regards to the situation and issue:
Basically each annotation represents a ride in a theme park and displays the ride name, current wait time and distance to that ride. At the moment since I am calling setUpMapView() when the view appears, all of the ride annotations are being added to the qTree each time, but are not being removed. This is the issue that I am trying to resolve, but I can't find a way to remove them from the qTree.

MKMapView has the method removeAnnotation:, which will remove a single annotation, and removeAnnotations: which will remove an array of annotations. It also has an annotations property which lets you the current array of annotations. You should be able to select and remove the annotations that you want to remove and then add new ones to replace them.

I think you could try finding user location like this
let locationManager: CLLocationManager = CLLocationManager()
(write this as a class property, not inside any viewDidLoad!)
then u instantly have locationManager coordinates.
self.mapView.removeAnnotations(annotationsToRemove as [AnyObject])
could you print the "annotationsToRemove as [AnyObject]" and tell us what is the content ?
actually all this code is suspicious:
let annotationsToRemove = (self.mapView.annotations as NSArray).mutableCopy() as! NSMutableArray
annotationsToRemove.removeObject(self.mapView.userLocation)
annotationsToRemove.removeObjectsInArray(objects as [AnyObject])
self.mapView.removeAnnotations(annotationsToRemove as [AnyObject])
you define a constant, then edit it with removeObjects and then pass it to removeAnnotations ? strange man, please get as many prints on these lines as you can and tell what they are so we can help

Related

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

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.

How to remove "trace" of a mark in swift

I'm working on a tracker app and I managed to pull some data from the server and update other user's so called track. But I have this mark .person, which appears on every step. How Should I remove it?
Polyline is drawn like this:
private func updateOnlineTrackOnMap() {
let locations = self.track?.points?.map { $0.location } ?? []
guard locations.count >= 2 else { return }
mapView.drawPolyline(withLocations: locations)
mapView.setMark(.person, to: locations.last!.coordinate)
}
But mapView.removeMark(.person) doesn't work.
Ok, there were some custom methods. I've managed to do the trick like so:
if let oldAnnotation = self.drawer.oldAnnotation {
mapView.removeAnnotation(oldAnnotation)
}
let annotation = MKPointAnnotation()
annotation.coordinate = locations.last!.coordinate
annotation.title = "Speed"
let speed = locations.last!.speed * 3.6
annotation.subtitle = String(format: "%.2f km/h", speed)
mapView.addAnnotation(annotation)
mapView.selectAnnotation(annotation, animated: false)
oldAnnotation = annotation
mapView.drawPolyline(withLocations: locations)
There's just a global variable to store current annotation coordinate. And then in mapView :viewFor: I wrote something like this:
if annotation is MKPointAnnotation {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "Online")
annotationView.image = rotatedArrow
annotationView.canShowCallout = true
return annotationView
}

Getting a nil in Swift 3?

I am creating an app where I have annotation view showing that when you click it shows on the DetailsViewController that annotation data. However, I get "Name", and "Address" data but for phone Number I am getting set as nil. So, if you guys can see my code & help me solve it, I will be appreciated it.
Here is my code:
import UIKit
import MapKit
protocol UserLocationDelegate {
func userLocation(latitude :Double, longitude :Double)
}
class NearMeMapViewController: ARViewController, ARDataSource, MKMapViewDelegate, CLLocationManagerDelegate {
var nearMeIndexSelected = NearMeIndexTitle ()
var locationManager : CLLocationManager!
var nearMeARAnnotations = [ARAnnotation]()
var nearMeRequests = [NearMeRequest]()
var delegate : UserLocationDelegate!
var place: Place?
override func viewDidLoad() {
super.viewDidLoad()
self.title = nearMeIndexSelected.indexTitle
self.locationManager = CLLocationManager ()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLHeadingFilterNone
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.dataSource = self
self.headingSmoothingFactor = 0.05
self.maxVisibleAnnotations = 30
getNearMeIndexSelectedLocation()
}
func getNearMeIndexSelectedLocation()
{
let nearMeRequest = MKLocalSearchRequest()
nearMeRequest.naturalLanguageQuery = nearMeIndexSelected.indexTitle
let nearMeregion = MKCoordinateRegionMakeWithDistance(self.locationManager.location!.coordinate, 250, 250)
nearMeRequest.region = nearMeregion
let nearMeSearch = MKLocalSearch(request: nearMeRequest)
nearMeSearch.start { (response : MKLocalSearchResponse?, error :Error?) in
for requestItem in (response?.mapItems)! {
let nearMeIndexRequest = NearMeRequest ()
nearMeIndexRequest.name = requestItem.name
nearMeIndexRequest.coordinate = requestItem.placemark.coordinate
nearMeIndexRequest.address = requestItem.placemark.addressDictionary?["FormattedAddressLines"] as! [String]
nearMeIndexRequest.street = requestItem.placemark.addressDictionary?["Street"] as! String!
nearMeIndexRequest.city = requestItem.placemark.addressDictionary?["City"] as! String
nearMeIndexRequest.state = requestItem.placemark.addressDictionary?["State"] as! String
nearMeIndexRequest.zip = requestItem.placemark.addressDictionary?["ZIP"] as! String
self.nearMeRequests.append(nearMeIndexRequest)
print(requestItem.placemark.name)
}
for nearMe in self.nearMeRequests {
let annotation = NearMeAnnotation(nearMeRequest: nearMe)
self.nearMeARAnnotations.append(annotation)
self.setAnnotations(self.nearMeARAnnotations)
}
}
}
func ar(_ arViewController: ARViewController, viewForAnnotation: ARAnnotation) -> ARAnnotationView {
let annotationView = NearMeARAnnotationView(annotation: viewForAnnotation)
// annotationView.delegate = self
annotationView.frame = CGRect(x: 0, y: 0, width: 150, height: 50)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.tapBlurButton(_:)))
annotationView.addGestureRecognizer(tapGesture)
return annotationView
}
func tapBlurButton(_ sender: UITapGestureRecognizer) {
if let annotationView = sender.view as? NearMeARAnnotationView {
if let detailsVc = storyboard?.instantiateViewController(withIdentifier: "DetailsViewController")
as? DetailsViewController {
detailsVc.annotation = annotationView.annotation
if let annotation = annotationView.annotation as? Place {
detailsVc.place = annotation
}
self.navigationController?.pushViewController(detailsVc, animated: true)
}
}
}
}
Just looking over your code quickly:
"\(nearMeAnnotation.nearMeRequest.phone)"
All the other ones have a forced unwrap, this one doesn't. Most probably the value is nil and since you ask for a string representation of a wrapped var that might really be nil sometimes.
I think you should use a default value everywhere instead of a forced unwrap, like:
"\(nearMeAnnotation.nearMeRequest.phone ?? "")"
but also:
"\(nearMeAnnotation.nearMeRequest.street ?? "") \(nearMeAnnotation.nearMeRequest.state ?? "") \(nearMeAnnotation.nearMeRequest.state ?? "") \(nearMeAnnotation.nearMeRequest.zip ?? "")"
With forced unwraps your application will crash if a certain value is not set. This could be handled more elegantly if they're really required, for example already in the constructor of your object. There's the root cause of the optionals you're seeing. In this case NearMeAnnotation.

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.

How to display time on route as google maps

I have created route with multiple annotations.
I want to display text between annotations which exactly as attached screen shot.
Can any one help please?
Thanks
I tried something which will show the distance between two annotation but not when you tap on the MKPolylineOverlay. One more important thing I am not maintaining any standards.
Here is my controller structure.
import UIKit
import MapKit
class RouteViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
//Rest of the code see below
}
First of all I'll add some annotation to map in the viewDidLoad delegate method as below.
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
let annotation1 = MKPointAnnotation()
annotation1.title = "Times Square"
annotation1.coordinate = CLLocationCoordinate2D(latitude: 40.759011, longitude: -73.984472)
let annotation2 = MKPointAnnotation()
annotation2.title = "Empire State Building"
annotation2.coordinate = CLLocationCoordinate2D(latitude: 40.748441, longitude: -73.985564)
let annotation3 = MKPointAnnotation()
annotation3.title = "Some Point"
annotation3.coordinate = CLLocationCoordinate2D(latitude: 40.7484, longitude: -73.97)
let arrayOfPoints = [ annotation1, annotation2, annotation3]
self.mapView.addAnnotations(arrayOfPoints)
self.mapView.centerCoordinate = annotation2.coordinate
for (index, annotation) in arrayOfPoints.enumerate() {
if index < (arrayOfPoints.count-1) {
//I am taking the two consecutive annotation and performing the routing operation.
self.directionHandlerMethod(annotation.coordinate, ePoint: arrayOfPoints[index+1].coordinate)
}
}
}
In the directionHandlerMethod, I am performing the actual request for direction as below,
func directionHandlerMethod(sPoint: CLLocationCoordinate2D, ePoint: CLLocationCoordinate2D) {
let sourcePlacemark = MKPlacemark(coordinate: sPoint, addressDictionary: nil)
let destinationPlacemark = MKPlacemark(coordinate: ePoint, addressDictionary: nil)
let sourceMapItem = MKMapItem(placemark: sourcePlacemark)
let destinationMapItem = MKMapItem(placemark: destinationPlacemark)
let directionRequest = MKDirectionsRequest()
directionRequest.source = sourceMapItem
directionRequest.destination = destinationMapItem
directionRequest.transportType = .Automobile
let directions = MKDirections(request: directionRequest)
directions.calculateDirectionsWithCompletionHandler {
(response, error) -> Void in
guard let response = response else {
if let error = error {
print("Error: \(error)")
}
return
}
//I am assuming that it will contain one and only one result so I am taking that one passing to addRoute method
self.addRoute(response.routes[0])
}
}
Next I am adding the polyline route on map in the addRoute method as below,
func addRoute(route: MKRoute) {
let polyline = route.polyline
//Here I am taking the centre point on the polyline and placing an annotation by giving the title as 'Route' and the distance in the subtitle
let annoatation = MKPointAnnotation()
annoatation.coordinate = MKCoordinateForMapPoint(polyline.points()[polyline.pointCount/2])
annoatation.title = "Route"
let timeInMinute = route.expectedTravelTime / 60
let distanceString = String.localizedStringWithFormat("%.2f %#", timeInMinute, timeInMinute>1 ? "minutes" : "minute")
annoatation.subtitle = distanceString
self.mapView.addAnnotation(annoatation)
self.mapView.addOverlay(polyline)
}
Next I am implementing the rendererForOverlay delegate method as below,
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.blueColor()
renderer.lineWidth = 2
renderer.lineCap = .Butt
renderer.lineJoin = .Round
return renderer
}
Next one is the important one delegate method which is viewForAnnotation. Here I am doing some things like placing the label instead of the annotation as below,
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.title != nil && annotation.title!! == "Route" {
let label = UILabel()
label.adjustsFontSizeToFitWidth = true
label.backgroundColor = UIColor.whiteColor()
label.minimumScaleFactor = 0.5
label.frame = CGRect(x: 0, y: 0, width: 100, height: 30)
label.text = annotation.subtitle ?? ""
let view = MKAnnotationView()
view.addSubview(label)
return view
}
return nil
}

Resources