如何保证异步请求中的正确顺序

时间:2017-06-20 07:36:51

标签: ios swift alamofire

我有一个iOS应用程序,它使用Alamofire发出URL请求。当它们之间的时间很短时,我有时会发现请求以错误的顺序到达。这与我理解的异步请求的性质有关。有没有办法保证请求的正确顺序?我一直在想你可以等待每个请求完成,因为你有一个完成处理程序,或者你可以在服务器端处理这个,每个请求都有一个时间戳,这样服务器就可以丢弃时间戳较低的请求。我不知道什么是最好的解决方案。

到目前为止我的代码:

Alamofire.request(
     defaults.string(forKey: "APIurl")! + path,
     method: httpMethod,
     parameters: parameters,
     encoding: JSONEncoding.default,
     headers: headers).responseJSON
     { response in

     // Check if the request was successful
     var success = false
     if (response.result.isSuccess) {
         let statusCode = response.response!.statusCode
         if (statusCode == 200) {
            success = true
        } else {
            showAlert("COULD_NOT_COMPLETE_TASK_TITLE", message: "TRY_AGAIN_LATER")
        }
    }

}

我使用滑块来更改介于0和100之间的值。因此,在我的情况下,请求的顺序至关重要。假设我将滑块从50更改为60.对于异步请求,它有时会先执行60然后执行50.这是一个问题,因为它以这种方式发送到我的API并将最新值(在本例中为50)保存在数据库中虽然我想要的值是60。

2 个答案:

答案 0 :(得分:0)

如果线程是串行的,那么在你的情况下,它的顺序将始终与你输入的相同。因此,在同一个串行线程上异步调用一些操作将强制操作保留该顺序。

你的案子中的问题是你没有打电话给这些行动,Alamofire正在打电话给他们。保留顺序,但这取决于接收和解析响应的时间。这意味着您可能无法控制被调用的异步操作的顺序。

您有2种序列化响应的方法:

  1. 在调用下一个请求之前,您需要等待每个响应完成。如果您的回答是标准的(所有看起来都很相似),您只需要一些管理器来存储一系列请求,并且在前一个请求完成之前不会调用新请求。这可能有点慢,因为没有理由(或者至少在你的情况下看起来那样)不能同时执行请求。

  2. 序列化响应,以便按照与输入相同的顺序调用它们。这意味着您可以随时调用请求,并随时调用响应。但是一旦收到回复,您将检查其他响应是否完整,只有在它们出现时才会触发回复。这也意味着让一些经理将序列化回复。

  3. 所以对于第二个你需要的东西:

    SerializedRequestManager.performRequest(request, myCallbackClosure)
    
    然后,管理器会将请求保存到一些请求包装器数组中,如:

    let requestWrapper = RequestWrapper(request, myCallbackClosure, isCompleted: false)
    self.requestPool.append(requestWrapper)
    AF.performRequest(request, myInternalClosure)
    

    然后在响应(myInternalClosure)上,您需要设置正确的包装器以响应true,然后从数组的开头刷新响应。然后必须从数组中删除所有完成的响应:

    requestWrapper.responseData = data // Same wrapper that was just added into the array
    requestWrapper.responseError = error // Same wrapper that was just added into the array
    requestWrapper.isCompleted = true
    self.flushResponses()
    

    然后是flushResponses

    var newPool = [RequestWrapper]() // This is where all the pending items will stay
    var shouldFlushResponse = true // Will be set to false with first request that was not completed
    self.requestPool.forEach { wrapper in
        if wrapper.isCompleted && shouldFlushResponse {
           wrapper.callback(wrapper.responseData, wrapper.responseError) // perform response closure
        } else {
           shouldFlushResponse = false
           newPool.append(wrapper)
        }
    }
    self.requestPool = newPool
    

    但是你需要在这里对多线程非常小心。数组requestPool上的所有操作都应该在同一个线程上完成,但它可能是你想要的任何线程。

答案 1 :(得分:0)

如果您的案件中的请求顺序很重要,那么您应该去NSOperationQueue,这是确保您的请求顺序的唯一方法。

关注this教程以获得边框构思