Asynchronous CloudKit完成处理程序和调度同步问题

Asynchronous CloudKit完成处理程序和调度同步问题,asynchronous,cloudkit,completionhandler,Asynchronous,Cloudkit,Completionhandler,我对云工具包有以下查询 func cloudKitManageUserPublicTable (typeOfOperation: Int, encriptedBabyName: String?, encriptedOllyKey:String?, result: (error: NSError?, userHasBeenFound: Bool?, ollYKeyHasBeenFound: Bool?, encriptedBabyNameFound: String?) -> Void){

我对云工具包有以下查询

func cloudKitManageUserPublicTable (typeOfOperation: Int, encriptedBabyName: String?, encriptedOllyKey:String?, result: (error: NSError?, userHasBeenFound: Bool?, ollYKeyHasBeenFound: Bool?, encriptedBabyNameFound: String?) -> Void){

    // OPERATION TYPES
    // 1 - search for user and add, link or update a key
    // 2 - search for user and check he has a key
    // 3 - search for a key
    // 4 - search for user and add a default one if has not been found

    print("cloudKitManageUserPublicTable - operation \(typeOfOperation)")
    var recordCounter = 0
    var publicUserRecord = CKRecord(recordType: "PublicUsers")
    let useriCloudID = NSUserDefaults.standardUserDefaults().objectForKey("useriCloudID") as! String

    var predicate = NSPredicate()
    switch typeOfOperation {
    case 1:
        predicate = NSPredicate(format: "useriCloudID == %@", useriCloudID)
    case 2:
        predicate = NSPredicate(format: "useriCloudID == %@", useriCloudID)
    case 3:
        predicate = NSPredicate(format: "encriptedOllyKey == %@", encriptedOllyKey!)
    default:
        print("no scenarios")
    }
    let cloudKitQuery = CKQuery(recordType: "PublicUsers", predicate: predicate)
    let queryOperation = CKQueryOperation(query: cloudKitQuery)
    let operationQueue = NSOperationQueue()
    let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase;
    queryOperation.database = publicDatabase
    queryOperation.recordFetchedBlock = { (record : CKRecord) -> Void in
        publicUserRecord = record
        recordCounter += 1
    }
    queryOperation.queryCompletionBlock = { (cursor: CKQueryCursor?, error: NSError?) -> Void in
            print("cloudKitManageUserPublicTable - # of record found - \(recordCounter)")
            if error != nil
            {
                // ERROR  STOP
                print("cloudKitManageUserPublicTable - error - \(error)")
                result(error: error, userHasBeenFound: nil, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
            }
            else
            {
                switch typeOfOperation {
                case 1:
                    // KEY FOUND, UPDATE
                    print("cloudKitManageUserPublicTable - search for user and add or update a key")
                    publicUserRecord["encriptedBabyName"] = encriptedBabyName!
                    publicUserRecord["encriptedOllyKey"] = encriptedOllyKey!
                    publicUserRecord["hasKey"] = true
                    publicDatabase.saveRecord(publicUserRecord) { (CKRecord: CKRecord?, error: NSError?) -> Void in
                            if error != nil
                            {
                                print("cloudKitManageUserPublicTable - creating key - UPDATE error \(error)")
                                result(error: error, userHasBeenFound: nil, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
                            }
                            else
                            {
                                print("cloudKitManageUserPublicTable - creating key - UPDATE OK")
                                result(error: error, userHasBeenFound: nil, ollYKeyHasBeenFound: true, encriptedBabyNameFound: nil)
                            }
                    }

                case 2:
                    print("cloudKitManageUserPublicTable - search for user and check it has a key")
                    if publicUserRecord.objectForKey("hasKey") as? Bool == false
                    {
                        print("cloudKitManageUserPublicTable - user do not have a key")
                        result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: false, encriptedBabyNameFound: nil)
                    }
                    else
                    {
                        print("cloudKitManageUserPublicTable - user has a key")
                        result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: true, encriptedBabyNameFound: nil)
                    }
                case 3:
                    if recordCounter == 0
                    {
                        print("cloudKitManageUserPublicTable - no record has this key")
                        result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: false, encriptedBabyNameFound: nil)
                    }
                    else
                    {
                        print("cloudKitManageUserPublicTable - \(recordCounter) records have this key")
                        result(error: nil, userHasBeenFound: nil, ollYKeyHasBeenFound: true, encriptedBabyNameFound: nil)
                    }
                case 4:
                    if recordCounter == 0
                    {
                        // NO USER FOUND, CREATE
                        print("cloudKitManageUserPublicTable - search for user and add a default one if has not been found")
//                        publicUserRecord["encriptedBabyName"] = ""
//                        publicUserRecord["encriptedOllyKey"] = ""
                        publicUserRecord["hasKey"] = false
                        publicUserRecord["useriCloudID"] = useriCloudID
                        publicDatabase.saveRecord(publicUserRecord) { (CKRecord: CKRecord?, error: NSError?) -> Void in
                            dispatch_async(dispatch_get_main_queue()) {
                                if error != nil
                                {
                                    print("cloudKitManageUserPublicTable - no user - CREATE error \(error)")
                                    result(error: nil, userHasBeenFound: false, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
                                }
                                else
                                {
                                    print("cloudKitManageUserPublicTable - no user found - CREATE ok")
                                    result(error: nil, userHasBeenFound: false, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
                                }
                            }
                        }
                    }
                    else
                    {
                        // USER FOUND - DO NOTHING
                        print("cloudKitManageUserPublicTable - user exists, do nothing for now")
                        result(error: nil, userHasBeenFound: true, ollYKeyHasBeenFound: nil, encriptedBabyNameFound: nil)
                    }
                default:
                    print("no scenarios")
                }
            }
    }
    operationQueue.addOperation(queryOperation)
}
上面的方法第一次被下面的方法调用,我等待完成处理程序返回,然后第二次调用上面的方法,然后验证
publicUserRecord[“hasKey”]=false
是否设置为false

但我的问题是。当我第二次调用该方法来验证
publicUserRecord[“hasKey”]
时,它返回尚未保存任何内容。如果我随后稍等片刻,并调用该方法第三次验证
publicUserRecord[“hasKey”]
,那么它会找到并验证它

因为我在做同样的调用,并且结果已经保存在第一个调用中,所以苹果服务器似乎有点滞后,或者我没有正确使用完成处理程序、dispatch\u async、dispatch\u sync?有什么想法吗

  func manageUserPublicTable(){

        tryAgainButtonOutlet.enabled = false
        let spinningActivity = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
        spinningActivity.labelText = "Talking to Apple Servers"
        spinningActivity.detailsLabelText = "Creating user credentials..."

        cloudKitManageUserPublicTable(1) { (error, userExists) -> Void in
            dispatch_sync(dispatch_get_main_queue()) {
                if error != nil
                {
                    spinningActivity.hide(true)
                    // let user try again
                    let optionMenu = UIAlertController(title: nil, message: "Are you all set to upload this record?!", preferredStyle: .ActionSheet)
                    let tryAgain = UIAlertAction(title: "Try again", style: .Default, handler: {
                        (alert: UIAlertAction!) -> Void in
                        self.tryAgainButtonOutlet.enabled = true
                    })
                    let cancelAction = UIAlertAction(title: "Not yet...", style: .Cancel, handler: {
                        (alert: UIAlertAction!) -> Void in
                        self.tryAgainButtonOutlet.enabled = true
                    })
                    optionMenu.addAction(tryAgain)
                    optionMenu.addAction(cancelAction)
                    if(isIPad()) {
                        optionMenu.popoverPresentationController!.permittedArrowDirections = UIPopoverArrowDirection()
                        optionMenu.popoverPresentationController!.sourceView = self.view
                        optionMenu.popoverPresentationController!.sourceRect = CGRectMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0, 1.0, 1.0)
                    }
                    self.presentViewController(optionMenu, animated: true, completion: nil)
                }
                else
                {
                    spinningActivity.hide(true)
                    self.manageEncriptedKey()
                }
            }
        }

    }

实际上,在保存数据和检索数据之间可能会有一段时间。没有具体说明这可能需要多长时间。通常不到几秒钟

因此,你必须让你的应用程序逻辑,使它不关心这一点。您已经保存了该记录,因此您的应用程序已经知道该记录的内容。您可以从回调传递记录,这样就不必再次查询它


另一种想法。你的功能对我来说有点大。1功能中的功能太多。这使得阅读变得困难。理想情况下,函数只能做一件事。

谢谢Edwin,这回答了问题。