Xamarin Forms App Crash on iOS when navigating away from mapView page

3409
4
02-26-2018 05:56 PM
MohammedHashmi
New Contributor

Hi,

We have a Xamarin Forms app that uses Custom Renderers for our Map Control/Page in iOS (Custom Renderers - Xamarin). 

We are facing an issue where the app crashes if the page which has the MapView is navigated away from, while the Map View (via the Esri.ArcGISRuntime.Xamarin.iOS v 100.2.1 package) is still rendering (i.e. draw status is in progress).

This is how the map view is initialized within the custom renderer

var mapView = new MapView();
var tiledLayer = new WebTiledLayer("URL");
var map = new Map();
map.Basemap.BaseLayers.Add(tiledLayer);
mapView.Map = map;

SetNativeControl(mapView)‍‍‍‍‍‍‍

If the page with the mapView control is navigated away from while the map is still rendering (ex. in cases of weak network connectivity it may take a while) the app crashes (both on a simulator or an iOS device) with the following crash log. If the map fully renders (draw status is complete) before the user navigates away from the page then it is fine.

Unhandled Exception:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'MapView'.
2018-02-27 12:42:52.438 xamarinmaps.app.iOS[4201:827354] Unhandled managed exception:
Cannot access a disposed object.
Object name: 'MapView'. (System.ObjectDisposedException)
(null)
2018-02-27 12:42:52.438 xamarinmaps.app.iOS[4201:827354] critical: Stacktrace:

2018-02-27 12:42:52.438 xamarinmaps.app.iOS[4201:827354] critical: 
Native stacktrace:

2018-02-27 12:42:52.645 xamarinmaps.app.iOS[4201:827354] critical:      0   xamarinmaps.app.iOS       0x000000010560fef4 mono_handle_native_crash + 244
2018-02-27 12:42:52.646 xamarinmaps.app.iOS[4201:827354] critical:      1   libsystem_platform.dylib            0x000000011b777f5a _sigtramp + 26
2018-02-27 12:42:52.646 xamarinmaps.app.iOS[4201:827354] critical:      2   ???                                 0x0000ffff00001fb6 0x0 + 281470681751478
2018-02-27 12:42:52.646 xamarinmaps.app.iOS[4201:827354] critical:      3   libsystem_c.dylib                   0x000000011b40d0eb abort + 127
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      4   xamarinmaps.app.iOS       0x00000001057c159f xamarin_unhandled_exception_handler + 47
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      5   xamarinmaps.app.iOS       0x0000000105674a44 mono_invoke_unhandled_exception_hook + 148
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      6   xamarinmaps.app.iOS       0x000000010560fcad mono_handle_exception_internal + 5805
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      7   xamarinmaps.app.iOS       0x000000010560e5f8 mono_handle_exception + 24
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      8   xamarinmaps.app.iOS       0x0000000105593f5f mono_amd64_throw_exception + 143
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      9   ???                                 0x0000000134eb0ae7 0x0 + 5182786279
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      10  xamarinmaps.app.iOS       0x00000001057c1197 xamarin_process_managed_exception_gchandle + 55
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      11  xamarinmaps.app.iOS       0x00000001057c1153 xamarin_ftnptr_exception_handler + 19
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      12  ???                                 0x000000013b3d8d13 0x0 + 5288856851
2018-02-27 12:42:52.647 xamarinmaps.app.iOS[4201:827354] critical:      13  ArcGIS-sim64                        0x00000001064633cf _ZNKSt3__18functionIFvPvEEclES1_ + 31
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      14  ArcGIS-sim64                        0x00000001062b0f08 _ZNK16Esri_runtimecore6Common6SignalIKNS_7Mapping8Geo_viewEJEEclERS4_ + 296
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      15  ArcGIS-sim64                        0x00000001060152ca _ZN16Esri_runtimecore7Mapping23Geo_view_draw_requested21draw_request_callbackEv + 50
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      16  ArcGIS-sim64                        0x0000000106c93698 _ZN16Esri_runtimecore12Map_renderer3Map9on_pulse_Ev + 3136
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      17  ArcGIS-sim64                        0x0000000106cac827 _ZN16Esri_runtimecore12Map_renderer12Pulse_thread8execute_Ev + 73
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      18  ArcGIS-sim64                        0x0000000107466560 _ZN16Esri_runtimecore6Common6Thread11thread_procEPS1_ + 50
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      19  ArcGIS-sim64                        0x0000000107468108 _ZNSt3__114__thread_proxyINS_5tupleIJNS_10unique_ptrINS_15__thread_structENS_14default_deleteIS3_EEEEPFvPN16Esri_runtimecore6Common6ThreadEESA_EEEEEPvSE_ + 44
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      20  libsystem_pthread.dylib             0x000000011b7896c1 _pthread_body + 340
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      21  libsystem_pthread.dylib             0x000000011b78956d _pthread_body + 0
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical:      22  libsystem_pthread.dylib             0x000000011b788c5d thread_start + 13
2018-02-27 12:42:52.648 xamarinmaps.app.iOS[4201:827354] critical: 
=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I have tried the following temporary work around which ends up introducing memory leaks but avoids the crash.

protected override void Dispose(bool disposing)
{
   if (NativeControl.DrawStatus == Esri.ArcGISRuntime.UI.DrawStatus.InProgress) 
   {
      NativeControl = null; //todo: possible mem leak??
      SetNativeControl(new MapView());
   }‍‍‍‍‍‍‍‍‍
}‍‍‍‍‍‍‍‍

I have also tried setting the MapView.Map property to null before it gets disposed within the Dispose method but it does not change anything, the app still crashes.

Is there a way to cancel an ongoing/pending draw before the MapView gets disposed or any other way the above issue can be fixed?

4 Replies
PaulTallett
New Contributor II

I have a similar crash but your workaround doesn't work for me. I notice you are not calling the base class Dispose method, I wonder if that is what helped you. It doesn't make any difference to my solution, nothing I do prevents the crash.

Could you post your entire custom renderer please?

Would appreciate some help from Esri.

Cheers,

Paul

0 Kudos
PaulTallett
New Contributor II

using Esri.ArcGISRuntime.UI.Controls;
using Messenger365;
using Messenger365.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomMapView), typeof(CustomMapViewRenderer))]
namespace Messenger365.iOS
{
public class CustomMapViewRenderer : ViewRenderer<CustomMapView, UIView>
{
bool disposed = false;
CustomMapView customMapView;
MapView mapView;
bool holding = false;
UILongPressGestureRecognizer gr;

protected override void OnElementChanged(ElementChangedEventArgs<CustomMapView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
customMapView = e.NewElement as CustomMapView;
if (Control == null && !disposed)
{
mapView = new MapView(); // BUG: If you repeatedly mash the map page and revisit it, after about 5 goes you get an "Unable to access disposed object"
customMapView.MapView = mapView;
mapView.GeoViewHolding += MapView_GeoViewHolding;
gr = new UILongPressGestureRecognizer(HandleLongPress) { AllowableMovement = 10000 };
gr.ShouldRecognizeSimultaneously = new UIGesturesProbe((r, o) => { return true; });
mapView.AddGestureRecognizer(gr);
holding = false;
SetNativeControl(mapView);
customMapView.DoInitialize();
}
}

if(e.OldElement != null)
{
mapView.GeoViewHolding -= MapView_GeoViewHolding;
mapView.RemoveGestureRecognizer(gr);
}
}

private void MapView_GeoViewHolding(object sender, GeoViewInputEventArgs e)
{
holding = true;
}

private void HandleLongPress(UILongPressGestureRecognizer longPress)
{
if (longPress.State == UIGestureRecognizerState.Ended && holding)
{
holding = false;
var pt = longPress.LocationInView(Control);
customMapView.OnLongPress(new Point(pt.X, pt.Y));
}
}

protected override bool ManageNativeControlLifetime => false;

protected override void Dispose(bool disposing)
{
disposed = true;
//if (mapView.DrawStatus == Esri.ArcGISRuntime.UI.DrawStatus.InProgress)
SetNativeControl(new MapView());
//base.Dispose(disposing);
}
}
}

0 Kudos
PaulTallett
New Contributor II

I was able to fix my issue by making my CustomMapView inherit from View instead of MapView (so it doesn't create the underlying MapView), and making my native MapView that I set as the control in the custom renderer as STATIC and reusing the same MapView over and over again. Also performance is much improved. It seems new'ing up MapViews a lot causes the crash.

I then used platform specific code to manipulate the MapView instead of using the Esri Forms bindings.

Cheers,

Paul

0 Kudos
MohammedHashmi
New Contributor

Hey Paul,

Would you be able to share your fixed code? Are you removing your static map view from the view hierarchy everytime you navigate away from the mapview? What is the impact on memory usage?

0 Kudos