【问题标题】:Synchronous fetching data NSOperationQueue or NSURLSessionNSOperationQueue 或 NSURLSession 同步获取数据
【发布时间】:2016-04-26 10:22:04
【问题描述】:

在我的应用中,当我们点击登录按钮时,我们必须进行 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

如果有其他更好的方法,请告诉我..

【问题讨论】:

    标签: ios swift nsoperationqueue nsurlsessiondatatask


    【解决方案1】:

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

    只有在响应到达时才会调用完成处理程序或块,因此您可以通过这种方式管理您的 api 调用。

    希望这会有所帮助:)

    【讨论】:

    • 这种方法是尝试过还是猜测过?因为,在数据任务中添加数据任务会给我一个错误
    • 不,我过去用过这个。我已经将来自完成处理程序的其他 api 的数据传递给 api。
    • 制作三种不同的方法来执行这三个操作。从方法一的完成处理程序调用方法 2 并传递所需的数据,并从方法 2 的完成处理程序调用方法 3 通过传递所需的数据。
    • 这个方法很好用,我以前也做过。
    • 谢谢你们 :-)
    【解决方案2】:

    归根结底,使用“完成处理程序”的传统方法的简化代码版本可能如下所示:

    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”future 的方法如下所示(使用 Promises 是非常相似的方法):

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

    上面的语句创建了一个由三个组成的任务。

    这种方法包含完整的错误处理,即使它可能并不明显。生产版本与上面的这个 sn-p 没有太大区别 - 它可能只是添加了一种取消方法。

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

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

    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”期货方法需要第三方库。取消需要另一个 - 或您自己的实现(这并不难),或一个提供所有功能的库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-05
      • 2021-03-09
      • 1970-01-01
      • 1970-01-01
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多