观察对象的Rxswift变化值

时间:2018-07-25 11:49:53

标签: swift observable rx-swift subscribe

对于Rx和反应性编程,我一般还是陌生的。我只是想使事情正常。我正在尝试向API(有关此问题的Github API)发出请求后填充对象:

要填充的对象:

class GithubUser {
    var login: String?
    var joinDate: Date?
    var email: String?
}

我尝试喂食的方式:

class GithubUserRepository {
    static func getUser() -> Observable<GithubUser> {
        let userObservable = BehaviorRelay<GithubUser>(value: GithubUser())
        let login = "Thiryn"
        // GithubService.sharedInstance.getUser does whatever async call to the github API to get a user profile
        GithubService.sharedInstance.getUser(login, success: { (userProfile) in
            userObservable.value.login = login
            userObservable.value.email = userProfile.email
            userObservable.value.joinDate = userProfile.joinedDate
        }) { (error) in
            print(error.localizedDescription)
        }
        return userObservable.asObservable()
    }
}

我如何消费

class ViewController: UIViewController {

    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        GithubUserRepository.getUser().subscribe(onNext: { (user) in
            print(user.login ?? "nope")
        }).disposed(by: self.disposeBag)
    }
}

结果是我第一次“不”,在执行请求之前,然后我成功地从请求中获得了结果,更改了对象的值,但是由于订阅的函数是错误的,所以我可能做错了此后再也没有执行。 有什么想法吗?谢谢!

编辑:我的尝试基于Reactive Values example from RxSwift

3 个答案:

答案 0 :(得分:2)

您不应像这样使用BehaviorRelay。 如果您希望此方法仅返回一个用户,则使用Single会更好。

class GithubUserRepository {
    static func getUser() -> Single<GithubUser> {
        return Single.create { single in
            let login = "Thiryn"
            GithubService.sharedInstance.getUser(login, success: { (userProfile) in
                let user = GithubUser()
                user.login = login
                user.email = userProfile.email
                user.joinDate = userProfile.joinedDate
                single(.success(user))
            }) { (error) in
                single(.error(error))
            }
            return Disposables.create {
                // single disposed
            }
        }
    }
}

并消费:

class ViewController: UIViewController {

    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        GithubUserRepository.getUser().subscribe(onSuccess: { (user) in
            print(user.login)
        }, onError: { error in
            print(error.localizedDescription)
        }).disposed(by: self.disposeBag)
    }
}

虽然没有测试此代码。只是让您知道它的外观。

答案 1 :(得分:2)

一些说明-

首先,将现有API服务包装到Observable中的方法是使用Observable.create {}。目前,您这样做的方式并不理想(例如,仅使用Relay来存储值)

第二,修改引用类型不视为可观察流上的“更改”。唯一被视为更改的事情实际上是向流中发出新值。 (例如relay.accept(newUser))。

对于您的情况,应遵循的方案是:

func myMethod() -> Observable<DataModel> { 
    return Observable.create { observer in 
        myAPIService.doRequest ( result in 
            ... do some stuff ...
            observer.onNext(result)
            observer.onCompleted()

            // or observer.onError(error) if it occured
        }

        return Disposables.create { }
    }
}

这是将API调用包装在Rx-y方法中的正确方法,该方法返回Observable对象。如果您想返回Single.create,可以对Single进行同样的操作。

您应该进一步了解Rx的工作原理,它不像操纵事物的当前“值”那么基本,因为流中的事物实际上并没有“值”,只是将值不断添加到对象中。现有流。

答案 2 :(得分:0)

您的value是引用类型。您需要每次将其更改为struct或重新实例化,然后按以下方式分配给userObservable

userObservable.accept(GithubUser(login: login, email: userProfile.email, joinDate: userProfile.joinedDate))