State
Threading And Lifecycle
Keep Unity state updates on the right thread and tie subscriptions to the owning lifecycle.
- Threading
- Token bags
- Read-only state
- Cleanup
Keep Unity object work on the main thread and keep subscription ownership tied to the lifecycle that owns the listener.
Threading
SourceSet is thread-safe.
Task.Run(() =>
{
Health.SourceSet(50);
});Off-thread writes are queued and applied on the main thread. The write request returns true when accepted, but Value, validation, version, and subscribers do not update until the main thread pump applies the pending state.
Off-thread writes are last-writer-wins while pending:
Task.Run(() =>
{
Health.SourceSet(90);
Health.SourceSet(80);
Health.SourceSet(70);
});
// Main thread later applies 70.Do not subscribe off-thread.
// Do not do this.
Task.Run(() => Health.Subscribe(OnHealthChanged));Create subscriptions on the Unity main thread, usually in Awake, OnEnable, or initialization code.
Notifications always run on the main thread.
Tokens and Token Bags
All AzState subscription methods return AzEventToken, except BindTwoWay, which returns IAzPausableToken because it controls two internal tokens.
AzEventToken token = Health.Subscribe(OnHealthChanged);
IAzPausableToken twoWay = ModelVolume.BindTwoWay(UiVolume);Token operations:
token.Pause();
token.Resume();
token.Dispose();Bag pattern:
private readonly AzEventTokenBag _bindings = new();
private void OnEnable()
{
Health.Subscribe(OnHealthChanged).AddTo(_bindings);
Score.BindTo(SetScoreText).AddTo(_bindings);
}
private void OnDisable()
{
_bindings.DisposeAll();
}BindTwoWay does not return AzEventToken, so it cannot be added to AzEventTokenBag. Store it separately:
private IAzPausableToken _twoWayBinding;
private void OnEnable()
{
_twoWayBinding = ModelVolume.BindTwoWay(UiVolume, snapToThisOnBind: true);
}
private void OnDisable()
{
_twoWayBinding?.Dispose();
_twoWayBinding = null;
}Read-Only State
Expose IReadOnlyAzState<T> when other code should observe but not write.
public sealed class GameState
{
private readonly AzState<int> _score = new(0);
public IReadOnlyAzState<int> Score => _score.AsReadOnly();
public void AddScore(int amount)
{
_score.SourceSet(_score.Value + amount);
}
}Read-only consumers can:
- read
Value - read
Version - read
HasValue - read
Schedule - subscribe
- subscribe mapped values
- subscribe changed values
- bind to setters
They cannot call SourceSet.
Reset and Cleanup
UnsubscribeAll
UnsubscribeAll removes every subscriber from one state but keeps the current value and version.
Health.UnsubscribeAll();Use it when the state owner is resetting subscriptions globally.
Most component subscribers should dispose their own tokens instead.
ResetToDefault
ResetToDefault removes subscribers, clears the value, resets the version, and clears pending writes.
Health.ResetToDefault();After this:
HasValueis falseVersionis 0- subscribers are gone
- pending writes are cleared
Use it for complete reuse or pool reset.
