Xamarin でネイティブオブジェクトを使う際に最近気をつけていること

Xamarin でネイティブクラス(UIViewやActivity)のオブジェクトを使った際、気をつけて使わないとクラッシュの元になったりします。

今回は最近はまって気をつけていることをご紹介します。

ネイティブオブジェクトから継承したら Dispose を書く

ネイティブオブジェクトを継承した場合、Dispose で参照を外しましょう。また、コードから new で作ったインスタンスは Dispose しましょう。

このとき、disposing の値を見て、この値が true でないときは処理をしないようにする必要があります。そうしないとUIスレッド外でこれが呼ばれたときにUIオブジェクトを触ってしまいクラッシュ、ということになります。

UIButton appendButton;

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    appendButton = new UIButton(new CGRect(10,10, 200, 48));
    View.AddSubview(appendButton);
}

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        if (appendButton != null)
        {
            appendButton.Dispose();
            appendButton = null;
        }
    }
    base.Dispose(disposing);
}

イベントハンドラメモリリークに注意

イベントハンドラにを使う場合、イベントハンドラの方向や内容によってはメモリリークしてしまいます。 内容とか方向とか考えるの面倒なので、僕は全部ラムダには書かず、全部メソッドにしています。

※ WeakEvent を使うところまではまだたどり着けておらず…あと MVVM フレームワークにお任せできるときはしてしまったほうがいいですね。

// こうせず
protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);
    takeButton.Click += (sender, e) => Debug.WriteLine("Hello");
}
// こうする
protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);
    takeButton.Click += HandleTakeButton;
}

void HandleTakeButton (object sender, EventArgs e)
{
    Debug.WriteLine("Hello")
}

protected override void OnDestroy ()
{
    base.OnDestroy ();

    if (_takeBtn != null)
    {
        _takeBtn.Click += _takeBtn_Click;
        _takeBtn.Dispose();
    }
}