Search code examples
iosxamarin.iosuikitdisposeui-thread

How do I clean up in Dispose if I can't call UIKit from another thread?


Most of my UIKit Dispose overrides do something with other views before they get destroyed:

protected override void Dispose (bool disposing)
{
    if (ScrollView != null) {
        ScrollView.RemoveObserver (this, new NSString ("contentOffset"));
        ScrollView.RemoveObserver (this, new NSString ("contentInset"));
        ScrollView = null;
    }

    base.Dispose (disposing);
}

I just recently realized that Dispose will run on finalizer thread if disposing is false.
In this case ScrollView.RemoveObserver will be called from non-UI thread which is Bad.

What's the safe way to do UIKit-related cleanup in Dispose?


Solution

  • If disposing is false, then you would probably be better off not calling that code.

    protected override void Dispose (bool disposing)
    {
        if (disposing)
        {
            if (ScrollView != null) {
                ScrollView.RemoveObserver (this, new NSString ("contentOffset"));
                ScrollView.RemoveObserver (this, new NSString ("contentInset"));
                ScrollView = null;
            }
        }
        base.Dispose (disposing);
    }
    

    As a more general answer to your question - assuming this code is in a UIViewController - it might be better to attach/detach these observers inside ViewDidAppear, ViewDidDisappear - then you can avoid this issue altogether.