Rxswift 改变观察对象的值
Posted
技术标签:
【中文标题】Rxswift 改变观察对象的值【英文标题】:Rxswift change value of observed object 【发布时间】:2018-07-25 11:49:53 【问题描述】:我对 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
【问题讨论】:
【参考方案1】:一些澄清 -
首先,将现有 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
,您可以对Single.create
执行相同的操作。
您应该进一步了解 Rx 的工作原理,它不像操纵事物的当前“值”那么基本,因为流中的事物实际上并没有“值”,它只是不断地将值添加到现有流。
【讨论】:
【参考方案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)
虽然没有测试此代码。这只是为了让您了解它的外观。
【讨论】:
【参考方案3】:您的value
是一个引用类型。您要么需要将其更改为struct
,要么每次都重新实例化它并分配给userObservable
,如下所示:
userObservable.accept(GithubUser(login: login, email: userProfile.email, joinDate: userProfile.joinedDate))
【讨论】:
您不能将这样的值分配给 Relay 或 Observable。以上是关于Rxswift 改变观察对象的值的主要内容,如果未能解决你的问题,请参考以下文章