I've found that running some code to display a location in maps view MKMapItem.openInMaps()
only works exactly 50% of the time.
In fact it precisely alternates between the MKPlacemark
being displayed and it not being displayed.
For example every 1st, 3rd, 5th, 7th ...nth time the code runs then it displays the place mark, but every 2nd, 4th, 6th, 8th ...mth time it runs, the place mark is not displayed.
This is 100% reproducible running the code posted below.
This seems like its a bug, but if so then I'm surprised its not been reported nor fixed previously. But given the fact the failures are precisely alternating between success and failure leads me to think there's something else going on, hence I'm posting here to see if anybody is familiar with this issue or there is something one is supposed to do which is missing from the code, or there is a workaround:
override func viewDidAppear(_ animated: Bool) {
displayMap()
}
func displayMap()
{
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString("1 Infinite Loop, Cupertino,California") { (placemark: [CLPlacemark]?, error: Error?) -> Void in
if error == nil
{
if let placemark = placemark, placemark.count > 0
{
let location = placemark.first
let latitude = (location?.location?.coordinate.latitude)!
let longitude = (location?.location?.coordinate.longitude)!
let coordinates = CLLocationCoordinate2DMake(latitude, longitude)
let regionDistance:CLLocationDistance = 100000
let regionSpan = MKCoordinateRegionMakeWithDistance(coordinates, regionDistance, regionDistance)
let options = [
MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: regionSpan.center),
MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: regionSpan.span)
]
let placemark = MKPlacemark(coordinate: coordinates, addressDictionary: nil)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = "Apple"
mapItem.phoneNumber = "(405) 123-4567"
mapItem.openInMaps(launchOptions: options)
}
}
else
{
assert(false, "Unable to geocode")
}
}
}
This is what the result looks like when the code is run for the first, third, fifth, seventh ... time
And this is the result when the code is run for the second, fourth, sixth, eighth... time
Notice in the failure screenshot that not only is the place mark not displayed on the map but the slide up is also empty.
(Currently observing this on 10.2 but have seen it on other versions too)
Yes, there seem to be a bug in mapItem.openInMaps
, which opens driving directions as an overlay.
As accurately described by @return0:
...I tried your code and the problem lies in the fact that once you have the location centered and showing, if you don't dismiss it and launch the app again it will not show...
mapItem.openInMaps
does dismiss the driving directions overlay (instead showing the new location)(*) A further oddity to that situation is that once that overlay is closed, the location disappears.
Force the directions overlay to go away by requesting more than one location. In practice, it means invoking Maps with twice the same location:
MKMapItem.openMaps(with: [mapItem, mapItem], launchOptions: options)
Workaround bonus
Even if the user taps on the anchor and requests driving direction, subsequent invocation to Maps from your application to that or a different location will not leave it hanging. In other words, it works as expected.
func displayMap(_ address:String, name:String, tph:String)
{
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(address) { (placemark: [CLPlacemark]?, error: Error?) -> Void in
assert(nil == error, "Unable to geocode \(error)")
if error == nil
{
if let placemark = placemark, placemark.count > 0
{
let location = placemark.first
let latitude = (location?.location?.coordinate.latitude)!
let longitude = (location?.location?.coordinate.longitude)!
let coordinates = CLLocationCoordinate2DMake(latitude, longitude)
let regionDistance:CLLocationDistance = 10000
let regionSpan = MKCoordinateRegionMakeWithDistance(coordinates, regionDistance, regionDistance)
let options = [
MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: regionSpan.center),
MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: regionSpan.span)
]
let placemark = MKPlacemark(coordinate: coordinates, addressDictionary: nil)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = name
mapItem.phoneNumber = tph
MKMapItem.openMaps(with: [mapItem, mapItem], launchOptions: options)
} else {
print("Something wrong with \(placemark)")
}
}
}
}
...and invocation
@IBAction func doApple() {
displayMap("1 Infinite Loop, Cupertino, California", name: "Apple", tph: "(408) 996–1010")
}
@IBAction func doMicrosoft() {
displayMap("One Microsoft Way, Redmond, WA", name: "Microsoft", tph: "1-800-MICROSOFT")
}
@IBAction func doIBM() {
displayMap("1 New Orchard Road. Armonk, New York", name: "IBM", tph: "(914) 499-1900")
}