7
votes

I'm having nothing but trouble with NSUbiquitousKeyValueStore and getting it to reliably sync across two devices. It's starting to drive me mad. Mad.

I watch my code make a call to:

[[NSUbiquitousKeyValueStore defaultStore] setObject:_someData forKey:@"SomeData"];
[[NSUbiquitousKeyValueStore defaultStore] synchronize];

But more times than not, the data never shows up on the other device.

I've seen it sync within a few seconds and other times I've waited for an hour and never seen a sync. I plug the devices into xcode and start debugging and sometimes the data suddenly pops up and other times it doesn't. Sometimes it does.

After making this call, quit and restarting the App, I see the old data if I read it, not the new data I supposedly just posted. On the same device.

When the App starts up, I make a call to:

_someData = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:@"SomeData"];

I'm assuming there is no init code that needs to be run. No example I've found does.

When it works, it works quite well.

Then tonight I was looking at the device logs and found this right after my last exit (and attempt to send data):

Jul  8 21:32:03 unknown syncdefaultsd[17296] <Warning>: Error writing storage for com.mycompany.myapp to /private/var/mobile/Applications/4AC8C56E-6060-408B-84F9-F7EC336221D9/Library/SyncedPreferences/com.mycompany.myapp.plist: Error Domain=NSCocoaErrorDomain Code=4 "The operation couldn’t be completed. (Cocoa error 4.)" UserInfo=0xde80d40 {NSFilePath=/private/var/mobile/Applications/4AC8C56E-6060-408B-84F9-F7EC336221D9/Library/SyncedPreferences, NSUnderlyingError=0xde80b20"The operation couldn’t becompleted. No such file or directory"}

That path is not the valid path from my Apps sandbox (wrong GUID), so I wonder if this is the root of my problems. I do delete and re-install the App a lot during development, so I wonder if there is some old path cached somewhere and it's trying to sync that data. Is there a way to clear it is?

I know all my entitlements are set up correctly since it does work sometimes.

[[NSUbiquitousKeyValueStore defaultStore] synchronize] is returning YES.

Has anyone else seen this problem or that error? Is there something else I need to be doing when my App starts up and when I send data to the cloud? According to the docs and examples, it seems pretty easy.

6
I am facing the same issue and it's driving me crazy! It's been for hours just trying to figure out why it's not syncing.Abdalrahman Shatou
I have the exact same problem. I found that deleting the apps' container often caused the issue to surface. Once both instances of an app have a valid container, they will sync correctly. Once you try to test 'first experience' by deleting the container, the app instance may never get the UBKV from icloud. I have yet to figure out if this would surface in a real-world situation or not.Ryan Nichols
This is what I am seeing as well. Wouldn't this situation arise if a user deleted the App from the device, then reinstalled it again, expecting to get their data from the cloud UBKV? In my case (a game), this is one of the cases I want to deal with.Roger Gilbrat

6 Answers

3
votes

I use this at launch and get immediate iCloud values or updateKVStoreItems: gets called in < 5 seconds.

- (void) initializeiCloud
{
    NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(updateKVStoreItems:) name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification object:store];
    if ([store boolForKey:@"fakeSyncBit"])
    {
        NSLog(@"in initiCloud setting syncbit NO");
        [store setBool:NO forKey:@"fakeSyncBit"];  
    }
    else
    {
        NSLog(@"in initiCloud setting syncbit YES");
        [store setBool:YES forKey:@"fakeSyncBit"];
    }
    [store synchronize];
    NSLog(@"icloud store is synchronized. updateKVStoreItems: should be called shortly"); 
}
2
votes

iCloud key-value store is not intended for use with data which requires regular frequent synchronization and it appears Apple does not guarantee the timeliness of these operations. Apple states:

The key-value store is intended for storing data that changes infrequently. If the apps on a device make frequent changes to the key-value store, the system may defer the synchronization of some changes in order to minimize the number of round trips to the server. The more frequently apps make changes, the more likely it is that later changes will be deferred and not show up on other devices right away.

If it is okay that your app does not synchronize immediately and your interest in this is to speed testing/debugging then it appears this will be a necessary frustration unless you change your technique.

2
votes

The documentation for NSUbiquitousKeyValueStore states how synchronize works in detail. I think the assumption from Roger is that when you call:

[[NSUbiquitousKeyValueStore defaultStore] synchronize];

that it will upload the data straight away (assuming a network connection). This is NOT the case. Calling synchronize simply takes the keys and values you have set in memory and persists them to the local on-disk cache. Once this is done, the system then notifies iCloud that there is data ready to be uploaded. The key piece of information is mentioned below the synchronize method documentation:

This method does not force new keys and values to be written to iCloud. Rather, it lets iCloud know that new keys and values are available to be uploaded. Do not rely on your keys and values being available on other devices immediately. The system controls when those keys and values are uploaded. The frequency of upload requests for key-value storage is limited to several per minute.

Link to documentation

In short, the system controls when your keys and values are uploaded to iCloud and calling synchronize simply stores a local cache of them and notifies iCloud of new data waiting to be uploaded.

0
votes

It might be a stale cache in the device's list of installed applications. Try deleting the app on the device and re-installing it. Or maybe reboot the device.

One sure thing is that you should file a report to bugreport.apple.com

0
votes

Check your device console [via the organizer in Xcode]. It probably contains helpful information. Your entitlements may not be correct, even if the empty defaultStore sync returns YES.

0
votes

In that case if you use jailbroken device you must delete AppSync before icloud and GameCenter support will work properly. Obviously I assume that you do have Apple dev account.