如何在NSOperation依赖关系之间传递结果?

时间:2014-06-25 09:36:47

标签: icloud nsoperation nsoperationqueue ios8 cloudkit

新的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。你可以在fetchOperation1的completionBlock中嵌入fetchOperation2的init,但是你放弃了NSOperation的依赖功能,我试图在这里使用它。

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

3 个答案:

答案 0 :(得分:6)

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

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

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

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

如果您不想创建操作子类,并且只是想避免嵌套,您可以考虑使用排队机制来提供更多控制,例如CDEAsynchronousTaskQueue

答案 1 :(得分:2)

只需在第一个块上方声明第二个操作,这样就可以设置要在其上获取的recordID,正如您对示例的编辑所示:

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设置为取消。因此,您不需要像自定义操作那样需要任何特殊的最终块。

答案 2 :(得分:1)

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

4 ways to pass data between operations in swift