3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Unity】StartCoroutine()で起動したコルーチンを止める場合はIDisposableにキャストしてDispose()を呼ぶべき

Posted at

はじめに

この記事を読んで、UniRxの Observable.FromCoroutine() でコルーチンを起動した場合は大丈夫だったような気がしたので調べました。

Observable.FromCoroutine() でコルーチンを起動した場合はちゃんと破棄される

Observable.Unity.cs のソースコードを読んだら IEnumeratorIDisposable にキャストして Dispose() を呼んでいました。

以下ソースコード抜粋:

Observable.Unity.cs
..

var d = enumerator as IDisposable;
if (d != null)
{
    d.Dispose();
}

..

念のため次のようなコンポーネントで実験してみましたが、コルーチンが終わる前に GameObject を消すとちゃんと disposed とログが出ました。

CoroutineTest.cs
using System.Collections;
using UniRx;
using UnityEngine;

public class CoroutineTest : MonoBehaviour
{
    private IEnumerator _enumerator;

    void Start()
    {
        Observable.FromCoroutine(this.Coroutine).Subscribe().AddTo(this);
    }

    private IEnumerator Coroutine()
    {
        Debug.Log("Coroutine start");

        using (Disposable.Create(() => Debug.Log("disposed")))
        {
            yield return new WaitForSeconds(3f);
        }

        Debug.Log("Coroutine end");
    }
}

IEnumerator は必ず IDisposable を実装している?

IEnumerator<T>

public interface IEnumerator : IDisposable, System.Collections.IEnumerator

なので必ず IDisposable なのですが、 IEnumerator

public interface IEnumerator

なので IDisposable であるとは限りません。

その点はドキュメントによると

列挙子オブジェクトには、次の特性があります。
・IEnumerator と IEnumeratorを実装します。 T は反復子の yield 型です。
・このクラスは、System.IDisposable を実装します。

とのことで、イテレータブロックで生成された IEnumerator は必ず IDisposable を実装しているようです。

StartCoroutine() を安全に使うには

StopCoroutine()IEnumeratorIDisposable にキャストして Dispose() を呼ぶとか気の利いたことはしてくれないので、自分でやります。

CoroutineTest.cs
using System;
using System.Collections;
using UniRx;
using UnityEngine;

public class CoroutineTest : MonoBehaviour
{
    private IEnumerator _enumerator;

    void Start()
    {
        _enumerator = this.Coroutine();
        this.StartCoroutine(_enumerator);
    }

    void OnDestroy()
    {
        (_enumerator as IDisposable)?.Dispose();
        this.StopCoroutine(_enumerator);
    }

    // コルーチンは好きなように書く
    private IEnumerator Coroutine()
    {
        ...
    }
}

感想

IEnumerator をフィールドに保存・止めるときにキャストして Dispose() を呼ぶ手間を考えると Observable.FromCoroutine() で起動したほうが楽そう。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?