Cysharp / R3

The new future of dotnet/reactive and UniRx.
MIT License
1.72k stars 70 forks source link

ReadOnlyReactiveProperty subscription problem after dispose #170

Closed artsemgorbatchev closed 3 months ago

artsemgorbatchev commented 3 months ago

I have only one EquipmentUI element in my game. when I try to update this element (initialize it a second, third, and so on time) something goes wrong. UpdateUIWithDelay is not called. I will be grateful if you can help me. If necessary, I can provide more information.

    public class EquipmentUI : MonoBehaviour
    {
        private IEquipmentModel model;
        private IDisposable subscription;

        public void Initialize(IEquipmentModel model)
        {
            this.model = model;
            UpdateUI(model.CurrentLevel.CurrentValue);

            subscription?.Dispose();
            subscription = model.CurrentLevel.SubscribeWithoutInitial(UpdateUIWithDelay);
        }
    }
    public class EquipmentModel : IEquipmentModel
    {
        private readonly ReactiveProperty<int> currentLevel;

        public ReadOnlyReactiveProperty<int> CurrentLevel => currentLevel;

        public EquipmentModel(int level)
        {
            currentLevel.Value = new ReactiveProperty<int>(level);
        }
    }
    public interface IEquipmentModel
    {
        ReadOnlyReactiveProperty<int> CurrentLevel { get; }
    }
    public static class SubscribeBinder
    {
        public static IDisposable SubscribeWithoutInitial<T>(this Observable<T> source, Action<T> onNext)
        {
            return source.Skip(1).Subscribe(onNext);
        }
    }
ArtichaTM commented 3 months ago

Happened to my project too: https://github.com/ArtichaTM/Nova3D/issues/2 Tried to repeat this, but unsuccessful. If summarize what scripts make this issue in current project:

  1. Made GameObject with script, that always working. Assigned ReactiveProperty<bool> Paused to this script.
  2. Made second object, that instantiates with each start of the game (not launching game, start gameplay). Added script with field DisposableBag Disposables and this line in Start():
    MainLogic.Instance.Paused
            .Skip(1) // Skipping first call because Paused by default
            .Where(x => x == true)
            .Subscribe(_ => Pause())
            .AddTo(ref Disposables)
            ;

    Pause() content doesn't matter for now. That fact is, if dispose Disposables on first instantiate then on second instantiate ReactiveProperty<bool> Paused won't call Pause() for some reason

neuecc commented 3 months ago

I would appreciate it if you could provide a minimal reproducible project. However, v1.1.0-v1.1.9 had issues with unsubscribing from ReactiveProperty, so I believe the problem you mentioned was occurring. Which version were you experiencing this issue with? Please try the latest v1.1.10.

ArtichaTM commented 3 months ago

Updated 1.1.2 -> 1.1.10, problem fixed. I forgot that R3 released in last month and updates are necessary for such projects. Thanks, @neuecc

artsemgorbatchev commented 3 months ago

In my case the update did not help. The problem occurs on v1.1.11

fneumeyer commented 2 months ago

@artsemgorbatchev Did you update both the Unity Package and the NuGet package? For me, this fixed it, too.