Rxswift 改变观察对象的值
Rxswift change value of observed object
总的来说,我对 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)
}
}
结果是我第一次"nope",在请求执行之前,我成功地从我的请求中得到了一个结果,改变了对象的值,但我可能做错了什么作为之后永远不会执行订阅的功能。
有什么想法吗?谢谢!
编辑:我的尝试基于 Reactive Values example from RxSwift
您的 value
是引用类型。您要么需要将其更改为 struct
,要么每次都重新实例化它并分配给 userObservable
,如下所示:
userObservable.accept(GithubUser(login: login, email: userProfile.email, joinDate: userProfile.joinedDate))
你不应该这样使用 BehaviorRelay。
如果您希望此方法仅 return 一个用户,使用 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)
}
}
虽然没有测试这段代码。这只是为了让您了解它的外观。
一些说明 -
首先,将现有 API 服务包装到 Observable 中的方法是使用 Observable.create {}
。你现在这样做的方式不是最理想的(例如使用中继来存储值)
其次,修改引用类型在可观察流上不被视为 "change"。唯一被认为是更改的实际上是发射 一个新值到流上。 (例如 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 方法中的正确方法,return 是一个 Observable
对象。如果你想 return 一个 Single
,你可以对 Single.create
做同样的事情。
你应该进一步阅读 Rx 的工作原理,它不像操纵当前 "value" 的东西那么基本,因为流中的东西实际上没有 "value",它只是不断将值添加到现有流中。
总的来说,我对 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)
}
}
结果是我第一次"nope",在请求执行之前,我成功地从我的请求中得到了一个结果,改变了对象的值,但我可能做错了什么作为之后永远不会执行订阅的功能。 有什么想法吗?谢谢!
编辑:我的尝试基于 Reactive Values example from RxSwift
您的 value
是引用类型。您要么需要将其更改为 struct
,要么每次都重新实例化它并分配给 userObservable
,如下所示:
userObservable.accept(GithubUser(login: login, email: userProfile.email, joinDate: userProfile.joinedDate))
你不应该这样使用 BehaviorRelay。 如果您希望此方法仅 return 一个用户,使用 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)
}
}
虽然没有测试这段代码。这只是为了让您了解它的外观。
一些说明 -
首先,将现有 API 服务包装到 Observable 中的方法是使用 Observable.create {}
。你现在这样做的方式不是最理想的(例如使用中继来存储值)
其次,修改引用类型在可观察流上不被视为 "change"。唯一被认为是更改的实际上是发射 一个新值到流上。 (例如 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 方法中的正确方法,return 是一个 Observable
对象。如果你想 return 一个 Single
,你可以对 Single.create
做同样的事情。
你应该进一步阅读 Rx 的工作原理,它不像操纵当前 "value" 的东西那么基本,因为流中的东西实际上没有 "value",它只是不断将值添加到现有流中。