Crash in map renderer on offline MMPK with world imagery

603
8
01-02-2024 01:13 PM
dmc76
by
New Contributor III

I'm consistently getting crashes in the map renderer on my iOS app.  I can pretty consistently get it to crash by either rotating the device from landscape to portrait or when I enable a mode in my app that rotates the map based on the compass heading and I move the tablet around for a bit.  I'm using an offline MMPK file in my MapView that has both hillshade and world imagery base layers and a couple of polygon features.  Changing the visibility of the hillshade/world imagery layers doesn't impact the crash occurrence.  I also have another test MMPK with an offline clip of the world street map base layer, no other features, and it doesn't seem to crash doing the same kind of stress test.

The specific line it is crashing on in the debugger is:

#12 0x0000000104e177cc in closure #1 in GeoMetalView.makeUIView(context:) at /Users/jenkins/jenkins/workspace/200.3.0/daily_swift_SDK_release/swift/ArcGIS/Sources/ArcGIS/Views/GeoCommonView.swift:352

EXC_BAD_ACCESS (code=1, address=0x2)

I can supply more information as directed.

Thanks!

-Dave

0 Kudos
8 Replies
dmc76
by
New Contributor III

Just a follow-up .. I tried eliminating anything that rotated the map (locked tablet rotation and disabled map rotation in my app) and it was still crashing, until I also eliminated setViewpointCenter() to recenter the map at the current gps coordinate.  When the map was fixed and neither setViewpointRotation() or setViewpointCenter() was called, it seemed to eliminate the crashing.

0 Kudos
DavidFeinzimer
Esri Contributor

Hi @dmc76, thank you for reaching out.

Would you mind providing a few more details to help profile this crash a bit more?

  1. Which version(s) of iOS?
  2. Which device(s) or simulator(s)?
  3. Is there a NavigationSplitView in the hierarchy of your app?
  4. Would you be able to provide a minimum reproducible sample of the crashing code?
dmc76
by
New Contributor III

I've been testing on a physical device (iPad 9th gen, iOS 17.2).  I'm not using a NavigationSplitView.  I'll see if I can get a more isolated bit of code to get to ya that's causing the problem.  On a side note, as I was trying to track down this crash I had put setViewpointCenter/setViewpointRotation inside of a DispatchQueue.main.async{Task{}} closure (I was grasping at straws, thought that maybe it needed to be in the ui thread), but doing that caused it to crash waaaaay more often, I'm not sure why that would matter, but I figured I'd pass it along.  In any case, the crash was occurring (just less frequently) when I was just calling the setViewpoint functions straight inside a .task(id){} off the MapView, although I don't know if I can be 100% sure it was happening in response to the setViewpoint call, it seems to be related.

DavidFeinzimer
Esri Contributor

Thank you for those additional details @dmc76.

I'm able to open your MMPK file in a map view and use the viewpoint methods without running into any issues so it'd be great if you'd be able to provide some isolated code.

0 Kudos
dmc76
by
New Contributor III

I believe I was able to isolate the cause of the crash.  I don't think you need my code, I'll just describe what's happening.  The gist of it is that I implemented CLLocationManager and started listening for location updates and heading updates.  Whenever I got a heading or location update, I updated a corresponding @State object within the ContentView that contains my MapViewReader/MapView. I have two .task() elements on the MapView for each of the state objects (one that called setViewpointRotation() and one that called setViewpointCenter() ).  I exaggerated the issue by creating a timer that updated the heading and gps location artificially, which caused the crash within seconds in the MapView, as I described in my original post.

My solution was to force serialization of the calls to setViewpointRotation and setViewpointCenter using an actor that checks for the existence of a previous Task() and waits for it to finish if it exists, then creates a new Task() that calls either the rotation or center function as needed. (The task approach would get overloaded and stop updating, but using the nonisolated keyword on the wrapper function in the actor works.) I hope I am explaining this correctly.... the net result here is that I believe those two functions are not thread safe.  I've had my test code running for quite some time now feeding random coordinates and incrementing headings and it has been crash free with the forced serialization.

I guess I should add that I would need to modify this approach if I have to use it to prevent the crash, as I don't want to pile up a bunch of tasks waiting to complete and force every heading or location update to "play back" until it catches up, it should ignore extra updates between the last one that just finished and the most recent one... but for now, at least it's not crashing.

-Dave

0 Kudos
DavidFeinzimer
Esri Contributor

Thanks for your updated findings @dmc76

 

Another method you might consider is the LocationDisplay class which is compatible with CLLocationManager. From what I can gather, using AutoPanMode.compassNavigation might get you the desired effect here.

 

Sample code

Sample documentation

0 Kudos
dmc76
by
New Contributor III

I've tried implementing the LocationDisplay, as you suggested, but it has its own set of quirks. 

It has a habit of getting confused with the rotation and spinning "the long way around" as it animates from the previous rotation to the current rotation (very disorienting for the map to do a 200+ degree spin). 

I believe it is also not compensating for device orientation (i.e. the map rotation is correct in portrait mode, but 90/180/270 degrees off when in landscape or upside-down portrait modes)... perhaps I could wrap the SystemLocationDataSource() to inject the device orientation offset into the headings, but I'm not sure the best approach for that. Swift is not my wheelhouse.   (LocationDataSource is not able to be inherited by a custom class, so that isn't a solution).  Until I can get this to function correctly in landscape orientation, it's not an option for this app.

That being said, even in portrait mode, I can't pinpoint exactly what's wrong, but the rotation component of the compassNavigation is just not behaving as I would expect, whereas my code using setViewpointRotation, feeding the heading+device orientation offset straight from CLLocationManager is working just fine, until it causes the map renderer to crash.

0 Kudos
DavidFeinzimer
Esri Contributor

Hi @dmc76, I'm sorry to hear that you encountered these other issues when you went to try LocationDisplay. Thank you for reporting these findings. We've opened issues to look into both.

 

Ref Swift 4923, 4925

0 Kudos