Igor Pantović
Igor Pantović

Reputation: 9246

RxSwift Driver gets disposed after first value

I've just started playing around with Rx and decided to try out making a simple OSX app using RxSwift.

Since my app has a login form, I've found that GithubSignup example is pretty similar to what I'm doing.

I'm, however having an issue that my Drivers get disposed after first value is emitted from them, and I can't figure out how or why. Since my code is really similar to one from the Github example, I must be overlooking something.

Here is my ViewModel:

class LoginVM {

    let isWorking: Driver<Bool>
    let loginEnabled: Driver<Bool>

    init(
        input: (
            email: Driver<String>,
            password: Driver<String>,
            loginRequests: Driver<Void>
        ),
        dependency: (
            RoundedClient
        )
    ) {
        self.isWorking = Variable(false).asDriver()

        let credentials = Driver
            .combineLatest(input.email, input.password){ (email: $0, password: $1) }

        let credentialsEmpty = credentials
            .map{ credentials in
                credentials.email.characters.count > 0 && credentials.password.characters.count > 0
            }
            .distinctUntilChanged()

        self.loginEnabled = Driver
            .combineLatest(credentialsEmpty, self.isWorking){ !($0 || $1) }
            .distinctUntilChanged()
    }

}

And here is my ViewController:

class LoginViewController: NSViewController {

    var screenManager: ScreenManager!

    @IBOutlet weak var emailField: NSTextField!
    @IBOutlet weak var passwordField: NSSecureTextField!
    @IBOutlet weak var loginButton: NSButton!
    @IBOutlet weak var loginSpinner: NSProgressIndicator!
    @IBOutlet weak var errorLabel: NSTextField!

    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let vm = LoginVM(
            input: (
                email: self.emailField.rx_text.asDriver(),
                password: self.passwordField.rx_text.asDriver(),
                loginRequests: self.loginButton.rx_tap.asDriver()
            ),
            dependency: RoundedClient.sharedInstance
        )

        vm.loginEnabled
            .driveNext{ [weak self] enabled in
                self?.loginButton.enabled = enabled
                self?.loginButton.alphaValue = enabled ? 1.0 : 0.5
            }.addDisposableTo(self.disposeBag)

        vm.isWorking
            .drive(self.loginSpinner.ex_animating)
            .addDisposableTo(self.disposeBag)
    }

}

Here is an example when I attach ".debug()" to credentialsEmpty driver on LoginVM:

2016-04-17 16:32:36.730: LoginViewController.swift:38 (init(input:dependency:)) -> subscribed
2016-04-17 16:32:36.731: LoginViewController.swift:38 (init(input:dependency:)) -> Event Next(false)
2016-04-17 16:32:39.081: LoginViewController.swift:38 (init(input:dependency:)) -> Event Next(true)
2016-04-17 16:32:39.081: LoginViewController.swift:38 (init(input:dependency:)) -> disposed

It is getting disposed as soon as value is emitted after initial one.

Upvotes: 2

Views: 2406

Answers (2)

Shiyason
Shiyason

Reputation: 781

I had this problem because I wrote

let disposeBag = DisposeBag()

inside the viewDidLoad method. Which effectively brought it out of scope as soon as the method finished.

Upvotes: 0

DeockJin Chung
DeockJin Chung

Reputation: 51

move your LoginVM instance variable to class member field.

let vm = LoginVM( ...

above 'vm' instance has locality in viewDidLoad() function

Upvotes: 1

Related Questions