11

新的 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 依赖项在其链中传递数据。

4

3 回答 3

7

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

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

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

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

如果您不想创建操作子类,而只是想避免块嵌套,则可以考虑使用一种队列机制,该机制为您提供更多控制权,例如CDEAsynchronousTaskQueue

于 2014-06-26T06:52:42.133 回答
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 设置为取消。因此,您不需要像自定义操作那样需要任何特殊的最终块。

于 2016-03-30T22:40:49.587 回答
1

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

快速在操作之间传递数据的 4 种方法

于 2017-09-12T07:17:11.373 回答