同步提取数据NSOperationQueue或NSURLSession

时间:2016-04-26 10:22:05

标签: ios swift nsoperationqueue nsurlsessiondatatask

在我的应用中,当我们点击登录按钮时,我们必须进行3次服务器调用。

1) will make a server call to get an OAuth token for user credentials
2) with the token from (1) we will get user privileges
3) with the token from (1) and with the valid privilege from (2) we will get the data to be displayed on the page after login in a tableview. 

我对此采取的方法感到困惑。使用operationqueue添加依赖项或使用NSURLSession任务是一种好方法吗?

根据其中一个堆栈溢出解决方案 - Best practices for making a queue of NSURLSessionTasks, NSURLSession没有任何关于排序请求的逻辑,即使在将每个主机的最大连接数设置为1时,它也会先调用任何完成的completionBlock

如果有其他更好的方法让我知道..

2 个答案:

答案 0 :(得分:1)

您可以使用NSURLSession个任务。首先调用第一个api方法,你将在完成处理程序(块)中得到响应。现在将它存储在任何公共属性中(因为你想再次使用它)在完成处理程序中。从该完成处理程序调用第二个api方法和第二个方法的完成处理程序,通过传递响应并使用存储了第一个api方法对象的公共属性来调用第三个api方法。

只有在响应到达时才会调用完成处理程序或块,这样您就可以管理api调用。

希望这会有所帮助:)

答案 1 :(得分:1)

在一天结束时,使用“完成处理程序”的传统方法的代码的简化版本可能如下所示:

fetchOAuthToken() { (token, error) in
    if let token = token {
        fetchPrivileges(token: token) { (privileges, error) in
            if let privileges = privileges {
               fetchData(token: token, privileges: privileges) { (data, error) in 
                   if let data = data {
                       // ... 
                   }
               }
            }
        }
    }
}

请注意,为简洁起见,代码不包含错误处理,也没有取消的方法。

依赖关系是通过 continuations 建立的 - 即完成处理程序。

利用“Scala-like”期货的另一种方法如下所示(使用 Promises 是非常相似的方法):

fetchOAuthToken().flatMap { token in
    fetchPrivileges(token: token).flatMap { privileges in
        fetchData(token: token, privileges).map { data in
            // ...
        }
    }
}.onFailure { error in
    print("Error: \(error)")
}

上面的陈述创建了一个由三个任务组成的任务。

这种方法包含完整的错误处理,即使它可能并不明显。生产版本与上面的这个片段没什么不同 - 它可能只会添加取消手段。

有一些第三方库实现类似Scala的期货或Promises。

添加取消的一种方法可能如下所示:

let cr = CancellationRequest()
fetchOAuthToken(ct: cr.token).flatMap { token in
    fetchPrivileges(token: token, ct: cr.token).flatMap { privileges in
        fetchData(token: token, privileges, ct: cr.token).map { data in
            // ...
        }
    }
}.onFailure { error in
    print("Error: \(error)")
}

稍后,您可以取消组合任务(当前正在执行的任务):

cr.cancel()

注意:

这个问题也可以NSOperations来解决。但是,它需要三个NSOperation的子类,以及一个或两个线程安全的辅助类,它们将用于将Op1的结果“传输”到Op2的输入,并将Op2的结果传递给Op3的输入。我估计这将需要大约500行代码 - 对SO的回答太多了;)

“Scala-like”期货方法需要第三方库。取消需要另一个 - 或您自己的实施(这并不困难),或一个提供一体化的库。