【问题标题】:Reference variable whose value is assigned inside block在块内赋值的引用变量
【发布时间】:2016-05-31 06:26:20
【问题描述】:

您对分配给完成块内的外部 ref 变量的值的范围感到困惑。例如,在下面的代码中, operationError 和 savedRecords 的值将在完成块之外持续存在。

    func applyLocalChangesToServer(insertedOrUpdatedCKRecords:Array<CKRecord>,deletedCKRecordIDs:Array<CKRecordID>) throws
    {
        var savedRecords:[CKRecord]?
        var conflictedRecords:[CKRecord] = [CKRecord]()
        var removeRecords:[CKRecord] = [CKRecord]()
        var operationError : NSError?

        let ckModifyRecordsOperation = CKModifyRecordsOperation(recordsToSave:insertedOrUpdatedCKRecords, recordIDsToDelete: deletedCKRecordIDs);
        ckModifyRecordsOperation.atomic = true
        ckModifyRecordsOperation.modifyRecordsCompletionBlock = ({(savedRecords1,deletedRecordIDs1,error)->Void in

            operationError = error

            if error == nil
            {
                wasSuccessful = true
                savedRecords = savedRecords1
            }
            else
            {
                wasSuccessful = false
                savedRecords = nil
                errorCKS = self.handleError(error!)
            }

        })
        ckModifyRecordsOperation.perRecordCompletionBlock = ({(ckRecord,error)->Void in

            if error != nil
            {  
                if error!.code == CKErrorCode.ServerRecordChanged.rawValue
                {
                    conflictedRecords.append(ckRecord!)
                }
            }

        })

        self.operationQueue?.addOperation(ckModifyRecordsOperation)
        self.operationQueue?.waitUntilAllOperationsAreFinished()

        if conflictedRecords.count > 0  
        {
            //Do work here

        }
        else if operationError != nil //Other then the partial error
        {
            throw operationError
        }

}

注意:由于 func applyLocalChangesToServer 抛出错误并且在 while 循环内,因此分配了 operationError。

【问题讨论】:

  • 你为什么要阻止和等待?为什么不从完成块中调用另一个函数?
  • 你的假设是正确的,这些在外壳范围内定义的变量将在完成处理程序执行后被修改。所以你的代码应该能按预期工作。
  • 一个观察 - self.operationQueue 必须在方法调用之前设置。如果未设置队列,我建议在代码中添加检查并抛出。
  • @wain 我需要反复调用这个函数,直到所有冲突都解决,所以我必须递归调用这个函数或者在 while 循环中使用。
  • @ignor B. 所以它们的值将一直持续到 applyLocalChangesToServer 函数的范围。 Okaies 将添加支票。

标签: ios swift scope closures block


【解决方案1】:

您的假设是正确的,这些在封闭范围内定义的变量将在完成处理程序执行后被修改。所以你的代码应该能按预期工作。

您还可以使用以下内容:

ckModifyRecordsOperation.main()

代替:

self.operationQueue?.addOperation(ckModifyRecordsOperation)
self.operationQueue?.waitUntilAllOperationsAreFinished()

希望对你有帮助。

【讨论】:

  • @ignor 我的困惑是关于 operationError 变量的生命周期,因为它是在完成处理程序中分配的,他们有可能以某种方式获得零。也就是说,如果闭包处理错误的生命周期,则 operationError = error 现在指向错误变量,它可能会被 nilled 并且 operationError 可能指向 nil。抱歉,这是一个愚蠢的问题,但我仍然对关闭的内存管理感到困惑
  • @user3519594 如果错误对象的类型是 reference 类型,那么你很好,因为 Swift 中的引用默认是 strong。这意味着当您将error 分配给operationError 时,将保留错误对象引用计数器。因此,直到 operationError 设置为 nil 或者它的范围结束 - 执行 applyLocalChangesToServer() 之前,错误对象才会被释放。如果错误对象的类型是 value 类型,那么你也很好,因为 operationError 有一个错误对象的副本 => 初始错误对象的生命周期不会影响你的复制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 1970-01-01
  • 2015-10-27
  • 2013-10-20
  • 2014-01-10
  • 2016-12-18
  • 1970-01-01
相关资源
最近更新 更多