Zenn
🗑️

VContainerでコンテナに登録されたオブジェクトの寿命・破棄処理

2025/01/02に公開

結論

  • LifetimeScopeのコンポーネントが破棄されると、登録クラスのすべてのIDisposable.Dispose()が呼ばれる
  • Lifetime.Transientの場合はIDisposable.Dispose()が呼ばれないので、自分で破棄処理を書く必要がある

これだけ!なのですが、もう少しかみ砕いて説明します。

作法

LifetimeScopeコンポーネントはシーン起動中常に生きるようにし、シーンの遷移に合わせて破棄されるようにするのが一般的です(RootLifetimeScopeは例外)。

これを前提とすると、LifetimeScope

  • シーン遷移時
  • ゲーム終了時

の2種類の場合でのみ破棄されることになります。

以下はこの作法を守っていること、そしてLifetime.SingletonLifetime.Scopedにて登録しているクラスであることを前提に説明します。

MonoBehaviourの寿命

MonoBehaviourのインスタンスは、VContainerとか関係なくシーンが遷移する際に同時に破棄されるため、特にこちら側で明示的な破棄を意識する必要はありません。

破棄が必要な参照を持っている場合は、VContainerを使っていない場合と同様にOnDestroy()で破棄処理を行います。

public class Sample : MonoBehaviour
{
    public ReadOnlyReactiveProperty<int> Value => _value;
    private readonly ReactiveProperty<int> _value = new ReactiveProperty<int>();

    void OnDestroy()
    {
        _value.Dispose();
    }
}

PureC#の破棄

LifetimeScopeコンポーネントの破棄時に登録クラスのIDisposable.Dispose()を呼んでくれる仕様になっていますので、PureC#のクラスはこれで対応します。

public class Sample : IDisposable
{
    CancellationTokenSource _cts = new CancellationTokenSource();

    public async UniTask SomeTask()
    {
        await UniTask.WaitForSeconds(10f, cancellationToken: _cts.Token);
    }

    // シーン遷移時など、コンテナオブジェクトが破棄されるときに自動で呼ばれる
    public void Dispose()
    {
        _cts?.Cancel();
        _cts?.Dispose();
    }
}
public class Sample : IStartable, IDisposable
{
    readonly SomeModel _model;

    CompositeDisposable _disposables = new CompositeDisposable();

    public MyService(SomeModel model)
    {
        _model = model;
    }

    public void Start()
    {
        _model.OnValueChangedAsObservable()
            .Subscribe(_ => Debug.Log("ValueChanged"))
            .AddTo(_disposables);
    }

    // シーン遷移時など、コンテナオブジェクトが破棄されるときに自動で呼ばれる
    public void Dispose()
    {
        _disposables?.Dispose();
    }
}

IAsyncStartableCancellationTokenの扱い

IAsyncStartable.StartAsync()を実装したエントリポイントクラスはCancellationTokenを受け取ることができます。

このCancellationTokenは、LifetimeScopeが破棄されるときに自動的にキャンセルされるようになっています。

public class SampleController : IAsyncStartable
{
    public async UniTask StartAsync(CancellationToken cancellation)
    {
        await UniTask.WaitForSeconds(10f, cancellationToken: cancellation);  // コンテナ破棄時にキャンセルされるので別途Dispose不要
    }
}

参考

https://vcontainer.hadashikick.jp/ja/scoping/lifetime-overview

Discussion

ログインするとコメントできます