MeXx
MeXx

Reputation: 3357

How to dispose DisposeBag when using ViewModelOwners with ReactiveCocoa

ViewModelOwners documents how to use with ReactiveCocoa CompositeDisposable

The Example is even implemented with ReactiveCocoa.

However, I do not understand how the disposeBag is actually disposed since CompositeDisposable does not dispose automatically on deinit

I'm trying the example and add a log message to the disposable:

func didSetViewModel(_: ViewModel, disposeBag: CompositeDisposable) {
  disposeBag += AnyDisposable {
    print("Disposed Profile")
  }
}

The message is never printed when the controller is deallocated.

I would think that you would need to dispose the bag manually on deinit, but the associated object is not exposed, so I can not get the disposeBag in deinit.

The best thing I came up with that works is using lifetime from ReactiveCocoa like this:

func didSetViewModel(_: ViewModel, disposeBag: CompositeDisposable) {
  disposeBag += AnyDisposable {
    print("Disposed Profile")
  }

  self.reactive.lifetime.observeEnded {
    if !disposeBag.isDisposed {
      disposeBag.dispose()
    }
  }
}

But this seems problematic, e.g. if this is a ReusableViewModelOwner, then all but the last disposeBags have already been disposed but I'm still retaining them...

So basically, my question is: How are you supposed use ViewModelOwners with ReactiveCocoa.CompositeDisposable?

Upvotes: 0

Views: 851

Answers (1)

MeXx
MeXx

Reputation: 3357

As mentioned in the question, ReactiveSwift.CompositeDisposable does not automatically dispose on deinit.

But ReactiveSwift already has a solution for this: ScopedDisposable which does exactly that.

So the solution to the original question is, to use ScopedDisposable<CompositeDisposable> instead of plain CompositeDisposable:

extension ScopedDisposable: ViewModelOwnerDisposeBagProtocol where Inner == CompositeDisposable {
    public convenience init() {
        self.init(CompositeDisposable())
    }

    private final class Wrapper: Disposable {
        var isDisposed: Bool
        let disposable: ViewModelOwnerDisposable

        init(_ disposable: ViewModelOwnerDisposable) {
            self.disposable = disposable
            isDisposed = false
        }

        func dispose() {
            disposable.dispose()
            isDisposed = true
        }
    }

    public func add(_ disposable: ViewModelOwnerDisposable) {
        inner.add(Wrapper(disposable))
    }
}

and then

func didSetViewModel(_ viewModel: ViewModel, disposeBag: ScopedDisposable<CompositeDisposable>) {
  disposeBag += AnyDisposable {
    print("Disposed Profile")
  }
}

The docs have already been updated accordingly

Upvotes: 1

Related Questions