RxSwift 的操作顺序
Sequence of actions with RxSwift
我正在使用 RxSwift 来简化我的代码。对于我当前的项目,我想将 RxSwift 的原则应用于 LayerKit 中的一堆完成块:
layerClient.connectWithCompletion { (success, error) -> () in
if (!success) {
// Error
} else {
layerClient.requestAuthenticationNonceWithCompletion { (nonce, error) -> () in
// Even more blocks
}
}
}
我在想这样的事情:
// In extension
public func rx_connect() -> Observable<Bool> {
return create { observer in
self.connectWithCompletion { (success, error) -> ()in
if (success) {
observer.on(.Next(success))
observer.on(.Completed)
} else {
observer.on(.Error(error))
}
}
return NopDisposable.instance
}
}
public func rx_requestAuthenticationNonce() -> Observable<String> {
// Same for annother method
}
// In AppDelegate
self.layerClient.rx_connect()
.then() // requestAuthenticationNonceWithCompletion and use the nonce for next action
.then()
.subscribeNext(…
.onError(… // To catch all errors
RxSwift 没有 then()
方法。有没有另一种方法来做这个链接的东西,或者我对如何使用 ReactiveX 的一般想法是错误的?
对,RxSwift 没有 then
运算符,因为这个名字非常危险。
then
在 Reactive Extensions 世界中可以是很多东西 a map
a flatMap
甚至 switchLatest
,具体取决于上下文。
在这种情况下,我建议使用 flatMap
,因为它将使用 map
返回,这是一个 Observable 的 Observable,在大多数情况下很难组合和管理。所以我会这样做:
self.layerClient.rx_connect()
.flatMap(){ _ in
return rx_requestAuthenticationNonce()
.catchError(displayError)
}
.subscribeNext(…
.onError(… // To catch all errors
在这种情况下,我会使用 flatMap
而不是 map
,因为如果 rx_requestAuthenticationNonce()
失败,我可以在不终止序列的情况下捕获错误。
小心使用catchError
运算符,此运算符将在恢复后终止序列,之后任何额外的事件都将被忽略。
这是我项目中的授权部分。只是链接请求的示例。它将链式请求的结果变成一个 bool 答案。它使用 'flatMap' 因为旧请求的结果用于构建新请求。否则,您可以使用 'concat' 而不是 'flatMap'。
let client = RxSimpleLazyHttpClient.sharedInstance
let uuid = UIDevice().identifierForVendor!.UUIDString
let helloheaders = ["X-User-Identifier": "id:" + uuid]
let helloRequest: Observable<StringDictionary> = client.makeRequest(verb: .GET, url: NSURL(string: self.API_HOST + self.API_HELLO)!, parameters: [:], headers: helloheaders)
.map { result in
if (self.enableDebugOutput) {
self.debug(result)
}
let json = JSON(data: result.2!)
let userKey = json["user_key"].string
let userSecretHash = json["user_secret_hash"].string
return ["user_key": userKey ?? "", "user_secret_hash": userSecretHash ?? ""]
}
let jointAuthRequest: (StringDictionary -> Observable<StringDictionary>) = { [unowned self] stringDictionary in
Logger.D(stringDictionary.debugDescription)
let userKey = stringDictionary["user_key"]
let headers = ["X-User": userKey ?? ""]
return client.makeRequest(verb: .GET, url: NSURL(string: self.API_HOST + self.API_AUTH)!, parameters: [:], headers: headers)
.map { result in
if (self.enableDebugOutput) {
self.debug(result)
}
let json = JSON(data: result.2!)
let nonce = json["nonce"].string
var result = [String: String]()
result["nonce"] = nonce
return result.merge(stringDictionary)
}
}
let jointAuthNonceRequest: (StringDictionary -> Observable<StringDictionary>) = { [unowned self] stringDictionary in
Logger.D(stringDictionary.debugDescription)
let nonce = stringDictionary["nonce"] ?? ""
let userSecretHash = stringDictionary["user_secret_hash"] ?? ""
let headers = ["X-Pass": (userSecretHash + nonce).sha1().webSafeBase64()]
return client.makeRequest(verb: .GET, url: NSURL(string: self.API_HOST + self.API_AUTH + "/" + nonce)!, parameters: [:], headers: headers)
.map { result in
if (self.enableDebugOutput) {
self.debug(result)
}
let json = JSON(data: result.2!)
let sessionKey = json["session_key"].string
let sessionSecret = json["session_secret"].string
var result = [String: String]()
result["session_key"] = sessionKey
result["session_secret"] = sessionSecret
return result.merge(stringDictionary)
}
}
let jointResult: (StringDictionary -> Observable<Bool>) = { result in
let userKey = result["user_key"]
let userSecretHash = result["user_secret_hash"]
let sessionKey = result["session_key"]
let sessionSecret = result["session_secret"]
if userKey == nil || userSecretHash == nil || sessionKey == nil || sessionSecret == nil {
Logger.D("Auth Fail")
return just(false)
}
/* You can store session key here */
return just(true)
}
return helloRequest
.shareReplay(1)
.observeOn(RxScheduler.sharedInstance.mainScheduler)
.flatMap(jointAuthRequest)
.flatMap(jointAuthNonceRequest)
.flatMap(jointResult)
这是'makeRequest'方法。
public func makeRequest(verb verb: Alamofire.Method, url: NSURL, parameters: [String : String]?, headers: [String : String]?) -> Observable<RxRequestResult> {
return create { observer in
Alamofire.request(verb, url, parameters: nil, encoding: ParameterEncoding.URL, headers: headers)
.response { request, response, data, error in
observer.onNext((request, response, data, error))
}
return AnonymousDisposable {
// when disposed
}
}
}
我正在使用 RxSwift 来简化我的代码。对于我当前的项目,我想将 RxSwift 的原则应用于 LayerKit 中的一堆完成块:
layerClient.connectWithCompletion { (success, error) -> () in
if (!success) {
// Error
} else {
layerClient.requestAuthenticationNonceWithCompletion { (nonce, error) -> () in
// Even more blocks
}
}
}
我在想这样的事情:
// In extension
public func rx_connect() -> Observable<Bool> {
return create { observer in
self.connectWithCompletion { (success, error) -> ()in
if (success) {
observer.on(.Next(success))
observer.on(.Completed)
} else {
observer.on(.Error(error))
}
}
return NopDisposable.instance
}
}
public func rx_requestAuthenticationNonce() -> Observable<String> {
// Same for annother method
}
// In AppDelegate
self.layerClient.rx_connect()
.then() // requestAuthenticationNonceWithCompletion and use the nonce for next action
.then()
.subscribeNext(…
.onError(… // To catch all errors
RxSwift 没有 then()
方法。有没有另一种方法来做这个链接的东西,或者我对如何使用 ReactiveX 的一般想法是错误的?
对,RxSwift 没有 then
运算符,因为这个名字非常危险。
then
在 Reactive Extensions 世界中可以是很多东西 a map
a flatMap
甚至 switchLatest
,具体取决于上下文。
在这种情况下,我建议使用 flatMap
,因为它将使用 map
返回,这是一个 Observable 的 Observable,在大多数情况下很难组合和管理。所以我会这样做:
self.layerClient.rx_connect()
.flatMap(){ _ in
return rx_requestAuthenticationNonce()
.catchError(displayError)
}
.subscribeNext(…
.onError(… // To catch all errors
在这种情况下,我会使用 flatMap
而不是 map
,因为如果 rx_requestAuthenticationNonce()
失败,我可以在不终止序列的情况下捕获错误。
小心使用catchError
运算符,此运算符将在恢复后终止序列,之后任何额外的事件都将被忽略。
这是我项目中的授权部分。只是链接请求的示例。它将链式请求的结果变成一个 bool 答案。它使用 'flatMap' 因为旧请求的结果用于构建新请求。否则,您可以使用 'concat' 而不是 'flatMap'。
let client = RxSimpleLazyHttpClient.sharedInstance
let uuid = UIDevice().identifierForVendor!.UUIDString
let helloheaders = ["X-User-Identifier": "id:" + uuid]
let helloRequest: Observable<StringDictionary> = client.makeRequest(verb: .GET, url: NSURL(string: self.API_HOST + self.API_HELLO)!, parameters: [:], headers: helloheaders)
.map { result in
if (self.enableDebugOutput) {
self.debug(result)
}
let json = JSON(data: result.2!)
let userKey = json["user_key"].string
let userSecretHash = json["user_secret_hash"].string
return ["user_key": userKey ?? "", "user_secret_hash": userSecretHash ?? ""]
}
let jointAuthRequest: (StringDictionary -> Observable<StringDictionary>) = { [unowned self] stringDictionary in
Logger.D(stringDictionary.debugDescription)
let userKey = stringDictionary["user_key"]
let headers = ["X-User": userKey ?? ""]
return client.makeRequest(verb: .GET, url: NSURL(string: self.API_HOST + self.API_AUTH)!, parameters: [:], headers: headers)
.map { result in
if (self.enableDebugOutput) {
self.debug(result)
}
let json = JSON(data: result.2!)
let nonce = json["nonce"].string
var result = [String: String]()
result["nonce"] = nonce
return result.merge(stringDictionary)
}
}
let jointAuthNonceRequest: (StringDictionary -> Observable<StringDictionary>) = { [unowned self] stringDictionary in
Logger.D(stringDictionary.debugDescription)
let nonce = stringDictionary["nonce"] ?? ""
let userSecretHash = stringDictionary["user_secret_hash"] ?? ""
let headers = ["X-Pass": (userSecretHash + nonce).sha1().webSafeBase64()]
return client.makeRequest(verb: .GET, url: NSURL(string: self.API_HOST + self.API_AUTH + "/" + nonce)!, parameters: [:], headers: headers)
.map { result in
if (self.enableDebugOutput) {
self.debug(result)
}
let json = JSON(data: result.2!)
let sessionKey = json["session_key"].string
let sessionSecret = json["session_secret"].string
var result = [String: String]()
result["session_key"] = sessionKey
result["session_secret"] = sessionSecret
return result.merge(stringDictionary)
}
}
let jointResult: (StringDictionary -> Observable<Bool>) = { result in
let userKey = result["user_key"]
let userSecretHash = result["user_secret_hash"]
let sessionKey = result["session_key"]
let sessionSecret = result["session_secret"]
if userKey == nil || userSecretHash == nil || sessionKey == nil || sessionSecret == nil {
Logger.D("Auth Fail")
return just(false)
}
/* You can store session key here */
return just(true)
}
return helloRequest
.shareReplay(1)
.observeOn(RxScheduler.sharedInstance.mainScheduler)
.flatMap(jointAuthRequest)
.flatMap(jointAuthNonceRequest)
.flatMap(jointResult)
这是'makeRequest'方法。
public func makeRequest(verb verb: Alamofire.Method, url: NSURL, parameters: [String : String]?, headers: [String : String]?) -> Observable<RxRequestResult> {
return create { observer in
Alamofire.request(verb, url, parameters: nil, encoding: ParameterEncoding.URL, headers: headers)
.response { request, response, data, error in
observer.onNext((request, response, data, error))
}
return AnonymousDisposable {
// when disposed
}
}
}