jlh*_*ora 46 ios swift alamofire promisekit
我正在寻找一个可以链接多个HTTP请求的好模式.我想使用Swift,最好是Alamofire.
比如说,我想做以下事情:
承诺的概念似乎很适合这一点.如果我可以做这样的事情,PromiseKit可能是个不错的选择:
NSURLConnection.promise(
Alamofire.request(
Router.Put(url: "http://httbin.org/put")
)
).then { (request, response, data, error) in
Alamofire.request(
Router.Get(url: "http://httbin.org/get")
)
}.then { (request, response, data, error) in
// Process data
}.then { () -> () in
// Reload table
}
Run Code Online (Sandbox Code Playgroud)
但那是不可能的,或者至少我不知道.
如何在不嵌套多个方法的情况下实现此功能?
我是iOS的新手,所以也许有一些我缺少的基础知识.我在其他框架(如Android)中所做的是在后台进程中执行这些操作并使请求同步.但Alamofire本质上是异步的,所以这种模式不是一种选择.
mxc*_*xcl 44
在promises中包装其他异步内容的工作方式如下:
func myThingy() -> Promise<AnyObject> {
return Promise{ fulfill, reject in
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]).response { (_, _, data, error) in
if error == nil {
fulfill(data)
} else {
reject(error)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:现在,使用:https://github.com/PromiseKit/Alamofire-
Eik*_*ike 27
我写了一个逐个处理请求链的类.
我创建了一个RequestChain以Alamofire.Request参数为基础的类
class RequestChain {
typealias CompletionHandler = (success:Bool, errorResult:ErrorResult?) -> Void
struct ErrorResult {
let request:Request?
let error:ErrorType?
}
private var requests:[Request] = []
init(requests:[Request]) {
self.requests = requests
}
func start(completionHandler:CompletionHandler) {
if let request = requests.first {
request.response(completionHandler: { (_, _, _, error) in
if error != nil {
completionHandler(success: false, errorResult: ErrorResult(request: request, error: error))
return
}
self.requests.removeFirst()
self.start(completionHandler)
})
request.resume()
}else {
completionHandler(success: true, errorResult: nil)
return
}
}
}
Run Code Online (Sandbox Code Playgroud)
我就是这样用的
let r1 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("1")
}
let r2 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("2")
}
let r3 = Alamofire.request(Router.Countries).responseArray(keyPath: "endpoints") { (response: Response<[CountryModel],NSError>) in
print("3")
}
let chain = RequestChain(requests: [r1,r2,r3])
chain.start { (success, errorResult) in
if success {
print("all have been success")
}else {
print("failed with error \(errorResult?.error) for request \(errorResult?.request)")
}
}
Run Code Online (Sandbox Code Playgroud)
重要的是您告诉管理员不立即执行请求
let manager = Manager.sharedInstance
manager.startRequestsImmediately = false
Run Code Online (Sandbox Code Playgroud)
希望它会帮助别人
Swift 3.0更新
class RequestChain {
typealias CompletionHandler = (_ success:Bool, _ errorResult:ErrorResult?) -> Void
struct ErrorResult {
let request:DataRequest?
let error:Error?
}
fileprivate var requests:[DataRequest] = []
init(requests:[DataRequest]) {
self.requests = requests
}
func start(_ completionHandler:@escaping CompletionHandler) {
if let request = requests.first {
request.response(completionHandler: { (response:DefaultDataResponse) in
if let error = response.error {
completionHandler(false, ErrorResult(request: request, error: error))
return
}
self.requests.removeFirst()
self.start(completionHandler)
})
request.resume()
}else {
completionHandler(true, nil)
return
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例Swift 3
/// set Alamofire default manager to start request immediatly to false
SessionManager.default.startRequestsImmediately = false
let firstRequest = Alamofire.request("https://httpbin.org/get")
let secondRequest = Alamofire.request("https://httpbin.org/get")
let chain = RequestChain(requests: [firstRequest, secondRequest])
chain.start { (done, error) in
}
Run Code Online (Sandbox Code Playgroud)
cno*_*oon 17
你有多种选择.
选项1 - 嵌套呼叫
func runTieredRequests() {
let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")
putRequest.response { putRequest, putResponse, putData, putError in
let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")
getRequest.response { getRequest, getResponse, getData, getError in
// Process data
// Reload table
}
}
}
Run Code Online (Sandbox Code Playgroud)
这绝对是我推荐的方法.将一个呼叫嵌入另一个呼叫非常简单,并且很容易遵循.它也让事情变得简单.
选项2 - 分裂成多种方法
func runPutRequest() {
let putRequest = Alamofire.request(.PUT, "http://httpbin.org/put")
putRequest.response { [weak self] putRequest, putResponse, putData, putError in
if let strongSelf = self {
// Probably store some data
strongSelf.runGetRequest()
}
}
}
func runGetRequest() {
let getRequest = Alamofire.request(.GET, "http://httpbin.org/get")
getRequest.response { [weak self] getRequest, getResponse, getData, getError in
if let strongSelf = self {
// Probably store more data
strongSelf.processResponse()
}
}
}
func processResponse() {
// Process that data
}
func reloadData() {
// Reload that data
}
Run Code Online (Sandbox Code Playgroud)
此选项密度较小,并将内容拆分为较小的块.根据您的需求和响应解析的复杂性,这可能是一种更具可读性的方法.
选项3 - PromiseKit和Alamofire
Alamofire可以轻松处理这个问题而无需拉入PromiseKit.如果你真的想走这条路,你可以使用@mxcl提供的方法.
这是使用DispatchGroup执行此操作的另一种方法(Swift 3,Alamofire 4.x)
import Alamofire
struct SequentialRequest {
static func fetchData() {
let authRequestGroup = DispatchGroup()
let requestGroup = DispatchGroup()
var results = [String: String]()
//First request - this would be the authentication request
authRequestGroup.enter()
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: FIRST Request")
results["FIRST"] = response.result.description
if response.result.isSuccess { //Authentication successful, you may use your own tests to confirm that authentication was successful
authRequestGroup.enter() //request for data behind authentication
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: SECOND Request")
results["SECOND"] = response.result.description
authRequestGroup.leave()
}
authRequestGroup.enter() //request for data behind authentication
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: THIRD Request")
results["THIRD"] = response.result.description
authRequestGroup.leave()
}
}
authRequestGroup.leave()
}
//This only gets executed once all the requests in the authRequestGroup are done (i.e. FIRST, SECOND AND THIRD requests)
authRequestGroup.notify(queue: DispatchQueue.main, execute: {
// Here you can perform additional request that depends on data fetched from the FIRST, SECOND or THIRD requests
requestGroup.enter()
Alamofire.request("http://httpbin.org/get").responseData { response in
print("DEBUG: FOURTH Request")
results["FOURTH"] = response.result.description
requestGroup.leave()
}
//Note: Any code placed here will be executed before the FORTH request completes! To execute code after the FOURTH request, we need the request requestGroup.notify like below
print("This gets executed before the FOURTH request completes")
//This only gets executed once all the requests in the requestGroup are done (i.e. FORTH request)
requestGroup.notify(queue: DispatchQueue.main, execute: {
//Here, you can update the UI, HUD and turn off the network activity indicator
for (request, result) in results {
print("\(request): \(result)")
}
print("DEBUG: all Done")
})
})
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
31574 次 |
| 最近记录: |