如何在 Swift 上同步或让 Observable 等待?

How to Synchronize or make an Observable wait on Swift?

所以,我有这个登录功能,我想 return 一个布尔值到我的 .xib 控制器,它必须根据登录的成功进行一些修改。

 func login(cpf: String) -> Bool {
    let url = URL(string: AccessibilityDataAccessProvider.kLoginURL)
    let params = ["username": String.init(describing: cpf)]

    var success = false

    dataAccessProvider.postSimpleResponse(url: url!, params: params)
        .subscribe(onNext: { (userToken) in
            let userData = UserDefaults.standard
            userData.set(userToken, forKey: AccessibilityDataAccessProvider.userTokenKey)
            userData.synchronize()
            success = true
    }, onError: { (error) in
        print("Login Error: \(error)")
    }).disposed(by: disposeBag)

    return success
}

来自 postSimpleResponse() 方法的 return 是 Observable 类型 Any?.

问题是,我的 login() 方法在 success 布尔变量设置为 true 之前 returning在订阅中。

我该如何解决这个问题?

你可以将 Observable 映射到一个 Bool observable(虽然这里 Bool 不是必需的,你可以只使用 Void),并且 return Observable 来自 login 方法。

像这样:

func login(cpf: String) -> Observable<Bool> {
    let url = URL(string: AccessibilityDataAccessProvider.kLoginURL)
    let params = ["username": String.init(describing: cpf)]

    return dataAccessProvider.postSimpleResponse(url: url!, params: params)
        .do(onNext: {
            let userData = UserDefaults.standard
            userData.set(userToken, forKey: AccessibilityDataAccessProvider.userTokenKey)
        })
        .map { _ in
            return true
    }
}

然后在上面观察:

login(cpf: "data").subscribe(onNext: { _ in
    // Success
}, onError: { _ in
    // Failure
}).disposed(by: disposeBag)

如前所述:

The whole point of Rx is that you model asynchronous tasks with Observables.

但是如果你真的需要让 observable 同步(等到 onNext,或者 onCompleted)你可以使用 DispatchGroup (monitor)。

您的代码应如下所示:

func login(cpf: String) -> Bool {
    let url = URL(string: AccessibilityDataAccessProvider.kLoginURL)
    let params = ["username": String.init(describing: cpf)]

    var result = false

    let group = DispatchGroup()
    group.enter()

    let subscription = dataAccessProvider.postSimpleResponse(url: url!, params: params)
        .subscribe(onNext: {
            let userData = UserDefaults.standard
            userData.set(userToken, forKey: AccessibilityDataAccessProvider.userTokenKey)

            result = true
            group.leave()
        }, onError: { _ in 
            group.leave()
        })

    group.wait() // wait till leave() method called
    subscription.dispose()

    return result
}

你应该记住,这种方法会阻塞当前线程,直到异步代码执行完毕。因此,它并不完美,但有时可能是必要的。