6

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

Odd

And this is the result when the code is run for the second, fourth, sixth, eighth... time

Even

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)

SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • 1
    Ok, So i tried your code and the problem lies in the fact that once you have the location centered and showing, if you dont dismiss it and launch the app again it will not show it. So, when you launch it and the info shows up, close the popup inside the Map app by pressing x and run it again, and it will work... That being said, I am not too sure what could be causing the problem exactly or how to get rid of it. – Munib Dec 31 '16 at 08:00
  • 1
    One more thing I noticed, is if there are any other previous notifications or locations zoomed upon inside the Map app, it will still not show your launch options. I clicked on my location inside the app, and it showed me a popup, I relaunched the app again and it was unable to show the options. So, I think that this is a bug. – Munib Dec 31 '16 at 08:05
  • @return0 thanks for the observations – Gruntcakes Dec 31 '16 at 16:04

2 Answers2

2

Disclaimer

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...

More Oddities

  1. The second time around, mapItem.openInMaps does dismiss the driving directions overlay (instead showing the new location)
  2. If the user closes said overlay, Map is no longer confused (*)

(*) A further oddity to that situation is that once that overlay is closed, the location disappears.

Bug? → Workaround!

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)

no directions, but not stuck directions but not stuck

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.


Complete Swift 3 Source Code

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")
}
Community
  • 1
  • 1
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
  • Thanks for your response – Gruntcakes Jan 07 '17 at 18:25
  • Great. Have you found your hamster yet? This was a rather interesting conundrum and I believe the solution will still work when Apple fixes that re-entry bug. – SwiftArchitect Jan 07 '17 at 21:25
  • This appears to be fixed now in iOS 10.3 beta 3 – Gruntcakes Mar 02 '17 at 16:32
  • Well done SwiftArchitect (this helped in my obj-c app as well). I used a version check for >= 10.0 and < 10.3 for the workaround, using the original mapItem.openMapsWithLaunchOptions() in the other case. Thanks! – Lytic Apr 11 '17 at 20:07
0

On iOS 10.3.2 this issue still persists for me. However, this workaround is making mapItem not to disappear:

MKMapItem.openMaps(with: [mapItem], launchOptions: options)
Andrey Gordeev
  • 30,606
  • 13
  • 135
  • 162