CloudKit完成处理程序和dispatch_sync问题

时间:2016-02-23 18:42:20

标签: asynchronous cloudkit completionhandler

我对Cloud Kit有以下疑问

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)
}

上面的方法通过下面的方法调用FIRST TIME,我等待完成处理程序返回,然后调用上面的方法进行SECOND TIME,然后验证publicUserRecord["hasKey"] = false是否设置为false。

但我的问题是。当我调用方法SECOND TIME来验证publicUserRecord["hasKey"]它返回时尚未保存任何内容。如果我稍等一下并调用该方法来验证第三次的publicUserRecord["hasKey"],那么它会找到并验证它。

由于我正在进行同样的调用并且结果已保存在FIRST调用中似乎与苹果服务器有点滞后或者我没有正确使用完成处理程序,dispatch_async,dispatch_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 个答案:

答案 0 :(得分:1)

确实可以在保存数据和检索数据之间留出一些时间。没有说明这可能有多长。通常它不到几秒钟。

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

另一个想法。你的功能有点大我的口味。 1功能中功能太多。这使得阅读起来很困难。理想情况下,函数应该只做一件事。