Reputation: 1783
I have the following query to 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)
}
The method above is called for the FIRST TIME by the method bellow where I wait for the completion handler to return and then call the method above for the SECOND TIME to then verify if the publicUserRecord["hasKey"] = false
was set to false.
But my problem is. When I call the method the SECOND TIME to verify the publicUserRecord["hasKey"]
it returns that nothing has been saved yet. If I then wait a bit and call the method to verify the publicUserRecord["hasKey"]
for the THIRD TIME then it finds and verifies it.
As I am doing the very same call and the results have been saved in the FIRST call seems that theres a bit of a lag with apple servers or am I not using the completion handlers, dispatch_async, dispatch_sync properly? Any ideas?
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()
}
}
}
}
Upvotes: 1
Views: 194
Reputation: 13127
Indeed there can be some time between saving data and being able to retrieve it. There is no specification how long this could be. Usually it's less than seconds.
So you have to make your app logic so that it does not care about that. You already saved the record so your app already knows the content of that record. You could pass on the record from the callback so that you don't have to query for it again.
One other think. Your functions are a bit large to my taste. There is too much functionality in 1 function. That makes it difficult to read. Ideally a function should do only one thing.
Upvotes: 1