【问题标题】:How to communicate results between NSOperation dependencies?如何在 NSOperation 依赖项之间传递结果?
【发布时间】:2014-08-15 19:23:27
【问题描述】:

新的 Cloud Kit 框架将 NSOperation 广泛用于其 CRUD。这些操作的结果以块的形式返回。例如:

let fetchOperation = CKFetchRecordsOperation(recordIDs: [recordID1, recordId2])

fetchOperation.fetchRecordsCompletionBlock = {(dict: NSDictionary!, error: NSError!) -> Void in
            // dict contains RecordId -> Record            
            // do something with the records here (if no error)
        }

我想链接其中一些操作(依赖项),并将操作的结果传递给链中的下一个操作。用于说明这一点的简化示例(伪代码!):

let fetchOperation1 = CKFetchRecordsOperation(recordIDs: [recordID1, recordId2])

fetchOperation1.fetchRecordsCompletionBlock = {(dict: NSDictionary!, error: NSError!) -> Void in
            if error {
              // handle error
            } else {
               // dict contains RecordId -> Record            
               // let's pretend our records contain references to other records
               // that we want to fetch as well
               fetchOperation.operationResult = 
                   dict.allValues().map(
                      { $0.getObject("referencedRecordId"}
               )
            }
        }

let fetchOperation2 = CKFetchRecordsOperation(recordIDs: fetchOperation1.operationResult)

fetchOperation2.fetchRecordsCompletionBlock = {(dict: NSDictionary!, error: NSError!) -> Void in
            if error {
              // handle error
            } else {
              // dosomething
            }
        }

fetchOperation2.addDependency(fetchOperation2)

但是上面的伪代码永远不能工作,因为当你初始化 fetchOperation2 时 fetchOperation1.operationResult 还没有分配。你可以将 fetchOperation2 的 init 嵌套在 fetchOperation1 的 completionBlock 中,但是你放弃了 NSOperation 的依赖功能,我在这里尝试使用它。

所以,我正在寻找一种干净、可读、标准(无反应可可等)的解决方案,让 NSOperation 依赖项在其链中传递数据。

【问题讨论】:

  • 如果您在第一个操作的完成块中创建第二个操作,则第二个操作将始终在第一个操作之后运行。如果您仍然可以按顺序执行,那么是否分配依赖关系又有何关系?
  • @TomHarrington 这是一个简化的例子。我有一个操作 A 将其结果发送到操作 B1 和操作 B2,它们需要将其结果发送到操作 C。嵌套变得非常快(又名“回调地狱”)并且需要一种模式来使其对“复杂”具有可读性'这样的情况。

标签: icloud nsoperation nsoperationqueue ios8 cloudkit


【解决方案1】:

我记得当NSOperation第一次被介绍时,我不得不为ADC网站写一篇介绍性文章,首先会下载一些照片,然后将它们渲染成海报。我在那里遇到了类似的问题:使用依赖项来控制顺序,但后来发现我必须将图像文件名传递给依赖项操作。

那是很多年前的事了,那时我每个任务都有NSOperation 子类。我设置了它们之间的依赖关系,并向需要传递早期操作结果的操作添加了一个委托。在委托方法中,控制器对象将从第一个操作的属性中检索结果,并通过第二个操作的属性设置它们。

也许更好的解决方案是明确操作之间的关系,不仅在依赖关系方面,而且在数据传递方面。因此,您可以创建 NSOperation 子类,将数据传递给下一个 NSOperation 作为标准操作的一部分,或者更优雅地从已完成的操作中提取数据。

为了更具体:操作 B 依赖于 A 的完成。 A 生成 B 运行所需的资源 R。您向 B 添加一个引用 A 对象的属性。当 B 运行时,它只是从 A 对象中检索 R。

如果您不想创建操作子类,而只是想避免块嵌套,您可以考虑使用队列机制,让您拥有更多控制权,例如CDEAsynchronousTaskQueue

【讨论】:

  • WWDC 2015 Advanced NSOperations 在这方面提供了很多东西。
  • 不幸的是它没有。共享数据的唯一示例是使用临时缓存文件在网络操作和解析操作之间共享数据。这就像隐藏的全局单例
【解决方案2】:

只需在第一个块上方声明第二个操作,以便您可以设置要在其上获取的记录 ID,如对示例的此编辑所示:

let fetchOperation1 = CKFetchRecordsOperation(recordIDs: [recordID1, recordId2])
let fetchOperation2 = CKFetchRecordsOperation()

fetchOperation1.fetchRecordsCompletionBlock = {(dict: NSDictionary!, error: NSError!) -> Void in
            if error {
              // handle error
            } else {
               // dict contains RecordId -> Record            
               // let's pretend our records contain references to other records
               // that we want to fetch as well
               fetchOperation2.recordIDs = 
                   dict.allValues().map(
                      { $0.getObject("referencedRecordId"}
               )
            }
        }

fetchOperation2.fetchRecordsCompletionBlock = {(dict: NSDictionary!, error: NSError!) -> Void in
            if error {
              // handle error
            } else {
              // dosomething
            }
        }

fetchOperation2.addDependency(fetchOperation1)

此外,如果您在第一个块中遇到错误,您应该取消队列上的所有操作。每个块仍将被调用,但会将 NSError 设置为取消。因此,您不需要像自定义操作那样需要任何特殊的 final 块。

【讨论】:

    【解决方案3】:

    在这里您可以找到 4 种不同的方法在 Swift 中的两个操作之间传递数据。

    4 ways to pass data between operations in swift

    【讨论】:

      猜你喜欢
      • 2015-03-20
      • 2015-12-23
      • 1970-01-01
      • 2021-07-26
      • 2018-12-31
      • 1970-01-01
      • 2013-02-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多