🗑️
VContainerでコンテナに登録されたオブジェクトの寿命・破棄処理
結論
LifetimeScope
のコンポーネントが破棄されると、登録クラスのすべてのIDisposable.Dispose()
が呼ばれる-
Lifetime.Transient
の場合はIDisposable.Dispose()
が呼ばれないので、自分で破棄処理を書く必要がある
これだけ!なのですが、もう少しかみ砕いて説明します。
作法
LifetimeScope
コンポーネントはシーン起動中常に生きるようにし、シーンの遷移に合わせて破棄されるようにするのが一般的です(RootLifetimeScope
は例外)。
これを前提とすると、LifetimeScope
は
- シーン遷移時
- ゲーム終了時
の2種類の場合でのみ破棄されることになります。
以下はこの作法を守っていること、そしてLifetime.Singleton
かLifetime.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();
}
}
IAsyncStartable
のCancellationToken
の扱い
IAsyncStartable.StartAsync()
を実装したエントリポイントクラスはCancellationToken
を受け取ることができます。
このCancellationToken
は、LifetimeScope
が破棄されるときに自動的にキャンセルされるようになっています。
public class SampleController : IAsyncStartable
{
public async UniTask StartAsync(CancellationToken cancellation)
{
await UniTask.WaitForSeconds(10f, cancellationToken: cancellation); // コンテナ破棄時にキャンセルされるので別途Dispose不要
}
}
参考
Discussion