Giter Site home page Giter Site logo

lhunath / ubiquitystoremanager Goto Github PK

View Code? Open in Web Editor NEW

This project forked from alekseyn/icloudstoremanager

390.0 29.0 37.0 1.65 MB

Implements Core Data + iCloud, deals with all the nasty stuff and gives you a clean API.

Home Page: http://lhunath.github.io/UbiquityStoreManager

License: Apache License 2.0

Objective-C 67.24% Shell 32.76%

ubiquitystoremanager's Introduction

Gittip Travis CI

I am no longer maintaining this project. I'm relying on some of the users of this project to step up and keep this project alive under iOS 8+ if there is continued interest in it.

About

UbiquityStoreManager is a controller that implements iCloud integration with Core Data for you, and takes away all the hardship.

When Apple first released the amazing Core Data integration with iCloud, it was a very simple API portrayed as trivial to integrate. Unfortunately, the contrary was certainly true. Apple has since made significant strides forward, especially in iOS 7. Nonetheless, there are still many caveats, side-effects and undocumented behaviors that need to be handled to get a reliable implementation.

UbiquityStoreManager also provides an immensely useful set of migration utilities for those interested in more control over their user's data than the "default" choices Apple has made for you.

Unfortunately, your users on iOS 6 still suffer a bunch of serious bugs in iCloud, which can sometimes lead to cloud stores that become desynced or even irreparably broken. UbiquityStoreManager handles these situations as best as possible.

The API has been kept as simple as possible while giving you, the application developer, the hooks you need to get the exact behavior you want. Wherever possible, UbiquityStoreManager implements safe and sane default behavior to handle exceptional situations but lets you make different choices if desired. The cases are well documented in the API documentation, as well as your ability to plug into the manager and implement your own custom behavior.

Disclaimer

I provide UbiquityStoreManager and its example application to you for free and do not take any responsability for what it may do in your application.

Creating and maintaining UbiquityStoreManager takes a huge amount of work. This code is provided to you free of cost, in the hopes that it will be useful to you in its current form or another. If this solution is useful to you, send me a thank-you note, or consider donating to the cause.

Note on iOS 7

Apple has significantly improved their Core Data integration with iCloud in iOS 7. Applications that wish to benefit from these improvements need to become iOS 7 only. UbiquityStoreManager has been updated with support for iOS 7. Devices running iOS 7+ (or OS X 10.9+) will initially migrate their old data over to a new iOS 7+ only store, and will hence forth sync only amoung other iOS 7+/OS X 10.9+ devices. iOS 6/OS X 10.8 devices will similarly only sync amoung each other. USM behaves this way to isolate the buggy old implementation of iCloud from the improved new implementation.

With iOS 7's improvements, why should you still use USM?

  • iOS 6 support: Apple now recommends all iCloud using apps be iOS 7-only. You may not necessarily agree.
  • Local Store: Apple has, for simplicity, decided that when the user enables iCloud on their phone in Settings, all apps that support iCloud will switch over to that iCloud account. More importantly, when a user wants to stop using iCloud, all his data is gone. USM gives you an application toggle that lets users switch between a ubiquitous store or a non-ubiquitous store.
  • Migration Utilities: USM comes with a vast amount of utilities to migrate between stores. Its API is simple and solves the problems your app will face: If your user wants to stop using iCloud, toggling iCloud off can, with one call, cause USM to switch to the local store and - if the user chooses - bring his cloud data with him to the local store.
  • iCloud is still not trivial: There are still a lot of things you need to do right. Just look at USM's vast code-base. If you use USM, all you do is -init an object, set a delegate and wait for us to give you a fully initialized NSPersistentStoreCoordinator. Let us take care of the work so you can focus on your data model and your app.

Getting Started

To get started with UbiquityStoreManager, all you need to do is instantiate it:

[[UbiquityStoreManager alloc] initStoreNamed:nil
                      withManagedObjectModel:nil
                               localStoreURL:nil
                         containerIdentifier:nil
                          storeConfiguration:nil
                                storeOptions:nil
                                    delegate:self];

The nil parameters can all be used to customize UbiquityStoreManager's behavior. For instance, if you already have a local store, you can pass its URL as the localStoreURL.

And then wait in your delegate for the manager to bring up your persistence layer:

- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager willLoadStoreIsCloud:(BOOL)isCloudStore {

    self.moc = nil;
}

- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator isCloud:(BOOL)isCloudStore {

    self.moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [moc setPersistentStoreCoordinator:coordinator];
    [moc setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
}

That’s it! The manager set up your NSPersistentStoreCoordinator, you created an NSManagedObjectContext, you’re ready to go.

Just keep in mind, as aparent from the code above, that your moc can be nil. This happens when the manager is not (yet) ready with loading the store. It can also occur after the store has been loaded (eg. cloud is turned on/off or the store needs to be re-loaded). So just make sure that your application deals gracefully with your main moc being unavailable. You can also observe the UbiquityManagedStoreDidChangeNotification which will be posted each time the availability of persistence stores changes (and always after your delegate is informed).

Initially, the manager will be using a local store. To enable iCloud (you may want to do this after the user toggles iCloud on), just flip the switch:

manager.cloudEnabled = YES;

If you prefer, you can use the -setCloudEnabledAndOverwriteCloudWithLocalIfConfirmed: and -setCloudDisabledAndOverwriteLocalWithCloudIfConfirmed: methods instead, which allow you to ask the user (via the confirmation block) if he wants to bring his current data with him when moving to the new (local or cloud) store. The confirmation block will only be triggered if necessary (the new store already exists). Data is migrated by default if the new store doesn't exist yet.

Surely I’m not done yet!

That depends on how much you want to get involved with what UbiquityStoreManager does internally to handle your store, and how much feedback you want to give your user with regards to what’s going on.

For instance, you may want to implement visible feedback for while persistence is unavailable (eg. show an overlay with a loading spinner). You’d bring this spinner up in ubiquityStoreManager:willLoadStoreIsCloud: and dismiss it in ubiquityStoreManager:didLoadStoreForCoordinator:isCloud:.

It’s probably also a good idea to update your main moc whenever ubiquity changes are getting imported into your store from other devices. To do this, simply provide the manager with your moc by returning it from -ubiquityStoreManager:managedObjectContextForUbiquityChanges: and optionally register an observer for UbiquityManagedStoreDidImportChangesNotification.

What if things go wrong?

And don’t be fooled: Things do go wrong. There are still some kinks, especially for your iOS 6/OS X 10.8 users. Some of these can cause the cloud store to become irreparably desynced.

UbiquityStoreManager does its best to deal with the issues, mostly automatically. Because the manager takes great care to ensure no data-loss occurs there are some rare cases where the store cannot be automatically salvaged. It is therefore important that you implement some failure handling, at least in the way recommended by the manager.

While it theoretically shouldn’t happen, sometimes ubiquity changes designed to sync your cloud store with the store on other devices can be incompatible with your cloud store. Usually, this happens due to an Apple iCloud bug in dealing with relationships that are simultaneously edited from different devices, causing conflicts that can’t be handled. Interestingly, the errors happen deep within Apple’s iCloud implementation and Apple doesn’t bother notifying you through any public API. UbiquityStoreManager implements a way of detecting these issues when they occur and deals with them as best it can.

Whenever problems occur with importing transaction logs (ubiquity changes), your application can be notified and optionally intervene by implementing ubiquityStoreManager:handleCloudContentCorruptionWithHealthyStore: in your delegate. If you just want to be informed and let the manager handle the situation, return NO. If you want to handle the situation in a different way than what the manager does by default, return YES after dealing with the problem yourself.

Essentially, the manager deals with import exceptions by unloading the store on the device where ubiquity changes conflict with the store and notifying all other devices that the store has entered a ”corrupted” state. Other devices may not experience any errors (they may be the authors of the corrupting logs, or they may not experience conflicts between their store and the logs). When any of these healthy devices receive word of the store corruption, they will initiate a store rebuild causing a brand new cloud store to be created populated by the old cloud store’s entities. At this point, all devices will switch over to the new cloud store and the corruption state will be cleared.

You are recommended to implement ubiquityStoreManager:handleCloudContentCorruptionWithHealthyStore: by returning NO but informing the user of what is going on. Here’s an example implementation that displays an alert for the user if his device needs to wait for another device to fix the corruption:

- (BOOL)ubiquityStoreManager:(UbiquityStoreManager *)manager
        handleCloudContentCorruptionWithHealthyStore:(BOOL)storeHealthy {

    if (![self.cloudAlert isVisible] && manager.cloudEnabled && !storeHealthy)
        dispatch_async( dispatch_get_main_queue(), ^{
            self.cloudAlert = [[UIAlertView alloc]
                    initWithTitle:@"iCloud Sync Problem"
                          message:@"\n\n\n\n"
                @"Waiting for another device to auto‑correct the problem..."
                         delegate:self
                cancelButtonTitle:nil otherButtonTitles:@"Fix Now", nil];
            UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]
                    initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
            activityIndicator.center = CGPointMake( 142, 90 );
            [activityIndicator startAnimating];
            [self.cloudAlert addSubview:activityIndicator];
            [self.cloudAlert show];
        } );

    return NO;
}

The above code gives the user the option of hitting the Fix Now button, which would invoke [manager rebuildCloudContentFromCloudStoreOrLocalStore:YES]. Essentially, it initiates the cloud store rebuild locally. More about this later.

Your app can now deal with Apple’s iCloud bugs, congratulations!

Unless you want to get into the deep water, you’re done now. What follows is for brave souls or those seeking for maximum control.

What else have you got?

UbiquityStoreManager tries its best to keep interested delegates informed of what’s going on, and even gives it the ability to intervene in non-standard ways.

If you use a logger, you can plug it in by implementing ubiquityStoreManager:log:. This method is called whenever the manager has something to say about what it’s doing. We’re pretty verbose, so you may even want to implement this just to shut the manager up in production.

If you’re interested in getting the full details about any error conditions, implement ubiquityStoreManager:didEncounterError:cause:context: and you shall receive.

If the cloud content gets deleted, the manager unloads the persistence stores. This may happen, for instance, if the user has gone into Settings and deleted the iCloud data for your app, possibly in an attempt to make space on his iCloud account. By default, this will leave your app without any persistence until the user restarts the app. If iCloud is still enabled in the app, a new store will be created for him. You could handle this a little differently, depending on what you think is right: You may want to just display a message to the user asking him whether he wants iCloud disabled or re-enabled. Or you may want to just disable iCloud and switch to the local store. You would handle this from ubiquityStoreManagerHandleCloudContentDeletion:.

If you read the previous section carefully, you should understand that problems may occur during the importing of ubiquitous changes made by other devices. The default way of handling the situation can usually automatically resolve the situation but may take some time to completely come about and may involve user interaction. You may choose to handle the situation differently by implementing ubiquityStoreManager:handleCloudContentCorruptionWithHealthyStore: and returning YES after dealing with the corruption yourself. The manager provides the following methods for you, which you can use for some low-level maintenance of the stores:

  • -reloadStore — Just clear and re-open or retry opening the active store.
  • -setCloudEnabledAndOverwriteCloudWithLocalIfConfirmed: — Enable iCloud if not yet enabled. If the user already has an iCloud store, your confirmation block is invoked allowing you to ask the user if he wants to either switch to the existing cloud data or overwrite it with his local data.
  • -setCloudDisableAndOverwriteLocalWithCloudIfConfirmed: — Disable iCloud if enabled. If the user already has a local store, your confirmation block is invoked allowing you to ask the user if he wants to either switch to the existing local data or overwrite it with his cloud data.
  • -migrateCloudToLocal — Manually overwrite the user's local data with the data in his iCloud store.
  • -migrateLocalToCloud — Manually overwrite the user's cloud data with the data in the local store.
  • -deleteCloudContainerLocalOnly: — All iCloud data for your application will be deleted. That’s not just your Core Data store!
  • -deleteCloudStoreLocalOnly: — Your Core Data cloud store will be deleted.
  • -deleteLocalStore — This will delete your local store (ie. the store that’s active when manager.cloudEnabled is NO).
  • -rebuildCloudContentFromCloudStoreOrLocalStore: — This is where the cloud store rebuild magic happens. Invoke this method to create a new cloud store and copy your current cloud data into it.

Many of these methods take a localOnly parameter. Set it to YES if you don’t want to affect the user’s iCloud data. The operation will happen on the local device only. For instance, if you run [manager deleteCloudStoreLocalOnly:YES], the cloud store on the device will be deleted. If cloudEnabled is YES, the manager will subsequently re-open the cloud store which will cause a re-download of all iCloud’s transaction logs for the store. These transaction logs will then get replayed locally causing your local store to be repopulated from what’s in iCloud.

USM will always try to be as non-destructive as possible. If a migration or operation fails, it will revert the user back to the state he was in before.

parseLogs

The parseLogs bash script allows you to analyse the output of Apple's verbose ubiquity log output and give you some feedback on it. It is in a very young stage, but is aimed at aiding with debugging any iCloud related sync issues.

parseLogs screenshot

To use the script, just run it (while in the directory of the script or after copying its bashlib dependency into PATH), feeding it the ubiquity log over STDIN:

./parseLogs < myapp.logs

To make it more verbose, add -v options. Verbose output will show unprocessed log lines as well. It is the aim of this script to process all log lines output by Apple's ubiquity logging. You can contribute either by amending the script or the LOGS summary file.

Under The Hood

UbiquityStoreManager tries hard to hide all the details from you, maintaining the persistentStoreCoordinator for you. If you're interested in what it does and how things work, read on.

Terminology

  • USM = UbiquityStoreManager, this project.
  • PSC = Persistent Store Coordinator, the object that coordinates between the store file, the store model, and managed contexts.
  • MOC = Managed Object Context, a "view" on the data store. Each context has their own in-memory idea of what the store's objects look like.

The Ideology

The idea behind USM was to create an implementation that hides all the details of loading the persistent store and allows an application to focus on simply using it.

To accomplish this, USM exposes only the API needed for an application to begin using a store, in addition to some lower-level API an application might need to handle exceptional situations in non-default ways. USM implements sane and safe default behavior for everything that isn't just "using the store", but allows an application to make different choices if it wants to.

There are different ways one may want to set up and configure their persistence layer. USM has made the following choices/assumptions for you:

  • There is a difference between the user's iCloud data and the user's local data:
    • When iCloud is disabled, an independant local store will be loaded. The user will not see their iCloud data.
    • When iCloud is enabled, the iCloud store will be loaded. This store will initially be a copy of the local store, but any changes will not be saved in the local store: they will only exist on the cloud.
  • The choice of whether iCloud is enabled or not is a device-specific one: enabling iCloud on one device does not cause all devices to suddenly switch over to iCloud.
    • Application developers are recommended to ask their user upon first start-up of the app whether they want iCloud enabled and allow them to switch it on or off with a setting.
  • When the user enables iCloud and there is no cloud store yet, a new iCloud store to be created and seeded by (filled up with) the data in the local store.
  • When the user enables iCloud on two devices at the same time, the last device that finishes seeding a cloud store will win, and both devices will begin using the winning cloud store.
  • When the user enables iCloud and there is already an active cloud store, the device will begin using the existing cloud store.
    • To allow users to re-seed the cloud store from a new device, USM provides utilities for deleting the cloud store. After deletion of the cloud store, enabling iCloud will cause a new store to be seeded from the local store again.
  • When a user manually deletes the cloud store from their iCloud account (eg. through their device's Settings), USM will clean up after it and switch back to the user's local store. The intention of the user was clearly to delete the data in the cloud.
    • An application hook exists which allows the application to decide how to handle the case, if they don't want USM to switch to the local store.
  • USM immediately unloads the cloud store if the user logs out of their iCloud account on the device or switches to another user's iCloud account. In the latter case, an iCloud store will be created on the new cloud account from the local store.

How Things Work

When initialized, USM will begin loading a store. Before any store is loaded, the application's delegate is first notified via willLoadStoreIsCloud:. At this point, the application may still make any chances it wishes to USM's configuration, and since this method is called from the internal persistence queue, it is in fact the recommended place to perform any initial configuration of USM. Do not do this from the method that called USM's init.

The cloudEnabled property determines what store will be loaded. If YES, USM will begin loading the cloud store. If NO, the local store.

The process of loading a local store is relatively simple. The directory hierarchy to the store file is created if it didn't exist yet, same thing for the store file. Automatic light-weight store model migration is enabled and mapping inference is as well. You can specify additional store loading options via USM's init method, such as file security options. If the store is loaded successfully, the application is notified and receives the PSC it needs to access the store via didLoadStoreForCoordinator:isCloud:. If the store fails to load for some reason, the application will not have access to persistence and is notified via failedLoadingStoreWithCause:context:wasCloud:. It can choose to handle this failure in some way.

The process of loading a cloud store is somewhat more involved. It's mostly the same as for the local store, but there is a bunch of extra logic:

  • If the cloud content no longer exists but the local cloud store file does, it is assumed the user wanted to delete their cloud data and the local store file is deleted.
  • If no cloud content exists, a new cloud store is created by migrating the local store's contents.
    • This new cloud store is identified by a random UUID.
    • The new UUID is kept locally until the migration and opening process for this store is a success.
    • Upon such success, this store is marked as the "active" cloud store by making its UUID ubiquitous.
  • If the cloud store fails to load once, a recovery attempt is made which deletes the local cloud store file and re-opens the cloud store, allowing iCloud to re-initialize the local cloud store file by importing all the cloud content again.
  • If the cloud store continues to fail loading, the store is marked as "corrupted".
  • If the store is successfully loaded, USM waits 20 seconds (to see if any cloud content will fail to import) and if no failure is detected, it checks to see if other devices have reported the cloud store as "corrupted". If so, cloud content recovery is initiated from this device which is, due to its success in loading the store, deemed healthy.

When a store is loaded, USM monitors it for deletion. When the cloud store is deleted, USM will clean up any "corruption" marker, the local cloud store file, and will fall back to the local store unless the application chooses to handle the situation via ubiquityStoreManagerHandleCloudContentDeletion:. When the local store is deleted, USM just reloads causing a new local store to be created.

The cloudEnabled setting is stored in NSUserDefaults under the key @"USMCloudEnabledKey". When USM detects a change in this key's value, it will reload the active store allowing the change to take effect. You can use this to add a preference in your Settings.bundle for iCloud.

Whenever the application becomes active, USM checks whether the iCloud identity has changed. If a change is detected and iCloud is currently enabled, the store is reloaded allowing the change to take effect. Similarly, when a change is detected to the active ubiquitous store UUID and iCloud is currently enabled, the store is also reloaded.

When ubiquitous changes are detected in the cloud store, your application's delegate can specify a custom MOC to use for importing these changes, so that it can become aware of the changes immediately. To do this, the application should return its MOC via -ubiquityStoreManager:managedObjectContextForUbiquityChanges:. If ubiquitous changes fail to import, the store is reloaded to retry the process and verify whether any corruption has occurred. Upon successful completion, the UbiquityManagedStoreDidImportChangesNotification notification is posted.

The cloud store is marked as "corrupted" when it fails to load or when cloud transaction logs fail to import. To detect the failure of transaction log import attempts made by Apple's Core Data, USM swizzles NSError's init method. This way, it can detect when an NSError is created for transaction log import failures and act accordingly.

When cloud "corruption" is detected the cloud store is immediately unloaded to prevent further desync. When the store is not healthy on the current device (the store failed to load or failed to import ubiquitous changes), USM will just wait and the persistence layer will remain unavailable. When the store is healthy on the current device, USM will initiate a rebuild of the cloud content by deleting the cloud content from iCloud and creating a new cloud store with a new random UUID, which will be seeded from the healthy local cloud store file. The new cloud store will be filled with the old cloud store's data and healthy cloud content will be built for it. Upon completion, the non-healthy devices that were waiting will notice a new cloud store becoming active, will load it, and will become healthy again. The application can hook into this process and change what happens by implementing handleCloudContentCorruptionWithHealthyStore:.

Any store migration can be performed by one of four strategies:

  • UbiquityStoreMigrationStrategyIOS: This strategy performs the migration via a coordinated migratePersistentStore: of the PSC. Some iOS versions have bugs here which makes this generally unreliable. This is the default strategy on iOS 7.
  • UbiquityStoreMigrationStrategyCopyEntities: This strategy performs the migration by copying over any non-ubiquitous metadata and copying over all entities, properties and relationships from one store to the other. This is the default strategy on iOS 6.
  • UbiquityStoreMigrationStrategyManual: This strategy allows the application's delegate to perform the migration by implementing manuallyMigrateStore:. This may be necessary if you have a really huge or complex data model or want some more control over how exactly to migrate your entities.
  • UbiquityStoreMigrationStrategyNone: No migration is performed and the new store is opened as-is.

License

UbiquityStoreManager is licensed under the Apache License, Version 2.0.

Feel free to use it in any of your applications. I’m also happy to receive any comments, feedback or review any pull requests.

Bitdeli Badge

ubiquitystoremanager's People

Contributors

alekseyn avatar bitdeli-chef avatar lhunath avatar orta avatar xhacker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ubiquitystoremanager's Issues

+entityForName: could not locate an NSManagedObjectModel for entity name 'Event''

I keep getting this error:
2013-11-20 09:04:36.100 iComplete3919:70b
2013-11-20 09:04:36.100 iComplete[3919:f03] UbiquityStoreManager: Loading store...
2013-11-20 09:04:36.103 iComplete[3919:f03] UbiquityStoreManager: Will load local store.
2013-11-20 09:04:36.108 iComplete[3919:f03] UbiquityStoreManager: Clearing stores...
2013-11-20 09:04:36.126 iComplete[3919:f03] UbiquityStoreManager: Will clear stores. Notifying application to reset its UI.
2013-11-20 09:04:36.149 iComplete[3919:f03] UbiquityStoreManager: Loading store: icomplete.sqlite
2013-11-20 09:04:36.175 iComplete[3919:f03] UbiquityStoreManager: Successfully loaded local store.
2013-11-20 09:04:36.177 iComplete[3919:f03] UbiquityStoreManager: Finished loading local store (UbiquityStoreErrorCauseNoError). Notifying application to refresh its UI.
2013-11-20 09:04:36.198 iComplete[3919:70b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Event''

The first "Null" is the NSLog in this code:

_manager = [[UbiquityStoreManager alloc] initStoreNamed:nil
                      withManagedObjectModel:[self managedObjectModel]
                               localStoreURL:[[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"icomplete.sqlite"]
                         containerIdentifier:nil
                      additionalStoreOptions:nil
                                    delegate:self];


NSLog(@"%@",managedObjectContext.description);

The fetch I am trying to do is in another object but I transfer the context like this:

- (void) fetch {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:[AppDelegate sharedAppDelegate].managedObjectContext];
    [fetchRequest setEntity:entity];

    // Create the sort descriptors array.
    NSSortDescriptor *authorDescriptor = [[NSSortDescriptor alloc] initWithKey:@"dueDate" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:authorDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(masterTaskID != nil)"];
    [fetchRequest setPredicate:predicate];

    NSError *error;
    self.events = [[managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];

}

I am probably giving the context to the other object incorrectly but I can't figure out where.

no iCloud available. Don't falling back to local cloud store?

Hey again,

and i probably found an error, when logged off from an iCloud Account over Settings.
After logged off, the Store Manager should fall back to his local cloud store file with iOS 7?

But the Store Manager do this:

2013-10-18 00:10:37.258 SeeMedia[3169:2e07] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: AndresimEEEF907B-8659-50FD-889A-B60E5405E8E1:32FE4655-603F-4BE0-84C2-B1C958B095CC
Using local storage: 1
2013-10-18 00:10:37.259 SeeMedia[3169:580b] StoreManager: Stores will change. Notifying application to reset its UI.
2013-10-18 00:10:37.326 SeeMedia[3169:a0b] StoreManager: Identity token changed: <8705bee0 fd3f041e 0bc0aaf4 f93c8cda 47bcd0db> -> (null)
2013-10-18 00:10:37.330 SeeMedia[3169:a0b] StoreManager: Identity token changed: (null) -> (null)
2013-10-18 00:10:37.331 SeeMedia[3169:580b] StoreManager: Reloading store...
2013-10-18 00:10:37.331 SeeMedia[3169:580b] StoreManager: Cannot load cloud store: User is not logged into iCloud. Falling back to local store.
2013-10-18 00:10:37.332 SeeMedia[3169:580b] StoreManager: Will load local store.
2013-10-18 00:10:37.332 SeeMedia[3169:580b] StoreManager: Clearing stores...
2013-10-18 00:10:37.332 SeeMedia[3169:2e07] -PFUbiquitySwitchboardEntry containerIdentifierChanged:: CoreData: Ubiquity: <PFUbiquitySwitchboardEntry: 0xa021780>:
localPeerID: Andre
simEEEF907B-8659-50FD-889A-B60E5405E8E1
ubiquityRootURL: <PFUbiquityLocation: 0xa250f00>: /Users/Andre/Library/Application Support/iPhone Simulator/7.0/Library/Mobile Documents/5X6CZTJ38PdehochschulteseemediaSeeMedia/CloudLogs/32FE4655-603F-4BE0-84C2-B1C958B095CC
registeredCoordinators: {
"32FE4655-603F-4BE0-84C2-B1C958B095CC" = "{(\n <_PFWeakReference: 0xa03a430>\n)}";
}

Error adding store for new account: Error Domain=NSCocoaErrorDomain Code=134080 "(null) is not a valid file URL" UserInfo=0x8a68820 {NSLocalizedDescription=(null) is not a valid file URL}
2013-10-18 00:10:37.333 SeeMedia[3169:580b] StoreManager: Will clear stores. Notifying application to reset its UI.
2013-10-18 00:10:37.334 SeeMedia[3169:580b] StoreManager: Loading store: SeeMedia.sqlite
2013-10-18 00:10:37.338 SeeMedia[3169:580b] StoreManager: Successfully loaded local store.
2013-10-18 00:10:37.339 SeeMedia[3169:580b] StoreManager: Reloading store...
2013-10-18 00:10:37.339 SeeMedia[3169:580b] StoreManager: Will load local store.
2013-10-18 00:10:37.339 SeeMedia[3169:580b] StoreManager: Clearing stores...
2013-10-18 00:10:37.340 SeeMedia[3169:580b] StoreManager: Will clear stores. Notifying application to reset its UI.
2013-10-18 00:10:37.343 SeeMedia[3169:580b] StoreManager: Loading store: SeeMedia.sqlite
2013-10-18 00:10:37.346 SeeMedia[3169:580b] StoreManager: Successfully loaded local store.
2013-10-18 00:10:37.347 SeeMedia[3169:580b] StoreManager: Finished loading local store (UbiquityStoreErrorCauseNoError). Notifying application to refresh its UI.

Example: Crash after pressing "Add button" in ios7

2013-10-02 11:57:49.700 UbiquityStoreManagerExample[7280:a0b] Starting UbiquityStoreManagerExample on device: iPhone Simulator

2013-10-02 11:57:49.723 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Loading store...
2013-10-02 11:57:49.723 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Will load cloud store.
2013-10-02 11:57:49.725 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Clearing stores...
2013-10-02 11:57:49.726 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-10-02 11:57:49.767 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Loading cloud store: C7D1ACE1-41B3-4B9A-9CE0-4E870388EB0F, v1 (definite).
2013-10-02 11:57:49.768 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: [DEBUG] migrationStoreURL: (null)
2013-10-02 11:57:49.769 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: [DEBUG] migrationStoreOptions: {
    NSInferMappingModelAutomaticallyOption = 1;
    NSMigratePersistentStoresAutomaticallyOption = 1;
    NSReadOnlyPersistentStoreOption = 1;
}
2013-10-02 11:57:49.785 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 0
2013-10-02 11:57:49.803 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: [DEBUG] Will NOT migrate to cloud store from: UbiquityStore.sqlite (strategy: 2).
2013-10-02 11:57:49.807 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Loading store: C7D1ACE1-41B3-4B9A-9CE0-4E870388EB0F.sqlite
2013-10-02 11:57:49.815 UbiquityStoreManagerExample[7280:1403] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  user~sim04F377BC-9AB6-5B48-AB50-15BEF7EFBFBA:C7D1ACE1-41B3-4B9A-9CE0-4E870388EB0F
Using local storage: 1
2013-10-02 11:57:49.869 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Successfully loaded cloud store.
2013-10-02 11:57:49.870 UbiquityStoreManagerExample[7280:1403] UbiquityStoreManager: Finished loading cloud store (UbiquityStoreErrorCauseNoError).  Notifying application to refresh its UI.
2013-10-02 11:57:51.389 UbiquityStoreManagerExample[7280:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'executeFetchRequest:error: A fetch request must have an entity.'
*** First throw call stack:
(
    0   CoreFoundation                      0x026fa5e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x018588b6 objc_exception_throw + 44
    2   CoreData                            0x0150fc0b -[NSManagedObjectContext executeFetchRequest:error:] + 5195
    3   UbiquityStoreManagerExample         0x000086c5 +[User primaryUserInContext:] + 277
    4   UbiquityStoreManagerExample         0x00002cb1 -[AppDelegate primaryUser] + 97
    5   UbiquityStoreManagerExample         0x00005494 -[MasterViewController insertNewObject:] + 196
    6   libobjc.A.dylib                     0x0186a874 -[NSObject performSelector:withObject:withObject:] + 77
    7   UIKit                               0x0005ec8c -[UIApplication sendAction:to:from:forEvent:] + 108
    8   UIKit                               0x00332e53 -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 139
    9   libobjc.A.dylib                     0x0186a874 -[NSObject performSelector:withObject:withObject:] + 77
    10  UIKit                               0x0005ec8c -[UIApplication sendAction:to:from:forEvent:] + 108
    11  UIKit                               0x0005ec18 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
    12  UIKit                               0x001566d9 -[UIControl sendAction:to:forEvent:] + 66
    13  UIKit                               0x00156a9c -[UIControl _sendActionsForEvents:withEvent:] + 577
    14  UIKit                               0x00155d4b -[UIControl touchesEnded:withEvent:] + 641
    15  UIKit                               0x0009c0cd -[UIWindow _sendTouchesForEvent:] + 852
    16  UIKit                               0x0009cd34 -[UIWindow sendEvent:] + 1232
    17  UIKit                               0x00070a36 -[UIApplication sendEvent:] + 242
    18  UIKit                               0x0005ad9f _UIApplicationHandleEventQueue + 11421
    19  CoreFoundation                      0x026838af __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    20  CoreFoundation                      0x0268323b __CFRunLoopDoSources0 + 235
    21  CoreFoundation                      0x026a030e __CFRunLoopRun + 910
    22  CoreFoundation                      0x0269fb33 CFRunLoopRunSpecific + 467
    23  CoreFoundation                      0x0269f94b CFRunLoopRunInMode + 123
    24  GraphicsServices                    0x026569d7 GSEventRunModal + 192
    25  GraphicsServices                    0x026567fe GSEventRun + 104
    26  UIKit                               0x0005d94b UIApplicationMain + 1225
    27  UbiquityStoreManagerExample         0x00001ddd main + 141
    28  libdyld.dylib                       0x05d3e725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException

If app launched due to an iOS 7 Background Fetch MOC never set

If you enable background updating in your app and then have your app launch due to a background fetch (either by an actual fetch time, or by setting the value in the scheme), the MOC is not getting set.

didLoadStoreForCoordinator, is never getting called.

The logs from launching this way are as follows:

UbiquityStoreManager: Loading store...
UbiquityStoreManager: Will load cloud store.
UbiquityStoreManager: Clearing stores...
UbiquityStoreManager: Will clear stores. Notifying application to reset its UI.

Thats it.
It never goes anywhere else.
If you launch normally then it works as expected.

Using UbiquityStoreManager with multiple local PersistentStores

I am trying to use two different PersistentStores, but one PersistentStoreCoordinator and one ManagedObjectContext. One PersistentStore would be a sqlite iCloud or local store (depending on the users choice) managed by UbiquityStoreManager and the other PersistentStore would always be a local core data sqlite store.

In researching this it appears the that the PersistentStoreCoordinator merges the ManagedObjectModels and that the only way to tell the PersistentStoreCoordinator that an added store only uses part of the merged ManagedObjectModel is to use configurations in the ManagedObjectModel. However, in the 5 places where addPersistentStoreWithType: is executed in UbiquityStoreManager.m the configuration is always set to nil (which equates to the Default configuration and excludes using configurations.)

I can add the local core data sqlite store to the coordinator using the following delegate code:

- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager 
  didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator
                     isCloud:(BOOL)isCloudStore
{
    NSPersistentStore *localStore = [coordinator persistentStoreForURL:[self myLocalStoreURL]];
    if (localStore == nil)
    {
        DDLogVerbose(@"Adding local store to store coordinator.");
        NSError *error = nil;
        [coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                  configuration:localConfig
                                            URL:[self myLocalStoreURL]
                                        options:@{NSMigratePersistentStoresAutomaticallyOption: @YES, NSInferMappingModelAutomaticallyOption: @YES}
                                          error:&error];
}

But I can't figure out how to get UbiquityStoreManager to associate the correct model with the PersistentStore it manages.

So should UbiquityStoreManager.m be changed or is there another, maybe better, approach that I am not aware of?

Notification if iCloud is disabled in Settings

Hey,

i have a question or maybe an issue. I'm missing a notification in your StoreManager, if the USer want to enable iCloud over the cloudEnabled switch, but iCloud is disabled in settings. It could be very important to notify the user of my app that he doesn't use the iCloud after try to enable it.

The store gets reloaded twice

The following code block taken from the current revision reloads the store twice (code summary):

- (void)setCloudEnabled:(BOOL)enabled {
...
    [[NSUserDefaults standardUserDefaults] setBool:enabled forKey:USMCloudEnabledKey];
    [self reloadStore];
}

- (void)userDefaultsDidChange:(NSNotification *)note {
    if (self.cloudWasEnabled != self.cloudEnabled)
        [self reloadStore];
}

Is this intended?

Wont compile on OS X 10.8

Getting a number of compiler errors when trying to compile on an OS X 10.8 target.

E.g. Use of undeclared identifier 'NSPersistentStoreUbiquitousContainerIdentifierKey'

  • this is a 10.9 only property.

Data always loads after a long delay

When you start the app, it always takes several seconds before the context is ready and you can display data.

For most apps this delay is not acceptable.

Other solutions show some sort of local cache right away while waiting for a connection with iCloud.

Example for replacing existing stores

Hi lhunath,

could you please post a small example which shows how to use the migrateStorewithOptions Method to replace the actual store with another backup store.

Thank you for your effords.

didLoadStoreForCoordinator fires before moc is ready to use

On the latest commit (and I'm not sure when this broken from 0.1.0), if I start making Core Data requests in this delegate method, I get exceptions which I cannot reproduce reliable. If I delay a second after this method ends, I never observe the exceptions.

Wont Sync Between Mac and iOS (10.9 and iOS 7)

I ran the Mac version of my app (10.9) and added data, waited 10 minutes, opened the iOS version (7) and nothing was there.
I deleted the app off my iPhone and off my Mac and went into Manage in iCloud and deleted the app data.
Waited 10 minutes, ran the Mac app, added new data, waited another 10 minutes, opened the iOS version and not only did the data not show up in the iOS app, but I also got the following logs.

2013-11-18 21:09:29.187 Shipment[476:1403] UbiquityStoreManager: Loading store...
2013-11-18 21:09:29.207 Shipment[476:1403] UbiquityStoreManager: Will load local store.
2013-11-18 21:09:29.209 Shipment[476:1403] UbiquityStoreManager: Clearing stores...
2013-11-18 21:09:29.209 Shipment[476:1403] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-18 21:09:29.385 Shipment[476:1403] UbiquityStoreManager: Loading store: UbiquityStore.sqlite
2013-11-18 21:09:29.449 Shipment[476:1403] UbiquityStoreManager: Successfully loaded local store.
2013-11-18 21:09:29.450 Shipment[476:1403] UbiquityStoreManager: Switching cloud disabled -> enabled
2013-11-18 21:09:29.450 Shipment[476:1403] UbiquityStoreManager: Reloading store...
2013-11-18 21:09:29.451 Shipment[476:1403] UbiquityStoreManager: Will load cloud store.
2013-11-18 21:09:29.451 Shipment[476:1403] UbiquityStoreManager: Clearing stores...
2013-11-18 21:09:29.451 Shipment[476:1403] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-18 21:09:29.924 Shipment[476:1403] UbiquityStoreManager: Error (cause:UbiquityStoreErrorCauseOpenActiveStore): Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x178262a80 {NSFilePath=/private/var/mobile/Library/Mobile Documents/FSBP7TQTJW~com~hashbangind~shipment/CloudLogs/StoreUUID+, NSUnderlyingError=0x178240330 "The operation couldn’t be completed. Bad file descriptor"}
2013-11-18 21:09:29.925 Shipment[476:1403] UbiquityStoreManager:     - Context   : /private/var/mobile/Library/Mobile Documents/FSBP7TQTJW~com~hashbangind~shipment/CloudLogs/StoreUUID+
2013-11-18 21:09:29.927 Shipment[476:1403] UbiquityStoreManager:     - Underlying: Error Domain=NSPOSIXErrorDomain Code=9 "The operation couldn’t be completed. Bad file descriptor"
2013-11-18 21:09:29.994 Shipment[476:1403] UbiquityStoreManager: Loading cloud store: 2407DB7B-A1F7-4521-80C9-3418DD5E989E, v1 (tentative).
2013-11-18 21:09:29.994 Shipment[476:1403] UbiquityStoreManager: [DEBUG] migrationStoreURL: (null)
2013-11-18 21:09:29.995 Shipment[476:1403] UbiquityStoreManager: [DEBUG] migrationStoreOptions: {
    NSInferMappingModelAutomaticallyOption = 1;
    NSMigratePersistentStoresAutomaticallyOption = 1;
    NSReadOnlyPersistentStoreOption = 1;
}
2013-11-18 21:09:29.995 Shipment[476:1403] UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 1
2013-11-18 21:09:29.996 Shipment[476:1403] UbiquityStoreManager: Will migrate to cloud store from: UbiquityStore.sqlite (strategy: 2).
2013-11-18 21:09:30.072 Shipment[476:1403] UbiquityStoreManager: Seeding store (strategy: UbiquityStoreMigrationStrategyIOS): CopyMigrationStore.sqlite -> 2407DB7B-A1F7-4521-80C9-3418DD5E989E.sqlite
2013-11-18 21:09:30.235 Shipment[476:1403] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  mobile~128B970C-34E8-44A1-A5B2-5CB304F76A79:2407DB7B-A1F7-4521-80C9-3418DD5E989E
Using local storage: 1
2013-11-18 21:09:30.254 Shipment[476:1403] UbiquityStoreManager: Confirming tentative StoreUUID: 2407DB7B-A1F7-4521-80C9-3418DD5E989E
2013-11-18 21:09:30.313 Shipment[476:1403] UbiquityStoreManager: Writing new StoreUUID:2407DB7B-A1F7-4521-80C9-3418DD5E989E to StoreUUID+ (v1).
2013-11-18 21:09:30.317 Shipment[476:1403] UbiquityStoreManager: Error (cause:UbiquityStoreErrorCauseConfirmActiveStore): Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x17007c7c0 {NSFilePath=/private/var/mobile/Library/Mobile Documents/FSBP7TQTJW~com~hashbangind~shipment/CloudLogs/StoreUUID+, NSUnderlyingError=0x1702443e0 "The operation couldn’t be completed. Bad file descriptor"}
2013-11-18 21:09:30.317 Shipment[476:1403] UbiquityStoreManager:     - Context   : /private/var/mobile/Library/Mobile Documents/FSBP7TQTJW~com~hashbangind~shipment/CloudLogs/StoreUUID+
2013-11-18 21:09:30.319 Shipment[476:1403] UbiquityStoreManager:     - Underlying: Error Domain=NSPOSIXErrorDomain Code=9 "The operation couldn’t be completed. Bad file descriptor"
2013-11-18 21:09:30.450 Shipment[476:1403] UbiquityStoreManager: Error (cause:UbiquityStoreErrorCauseOpenActiveStore): Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x17007c880 {NSFilePath=/private/var/mobile/Library/Mobile Documents/FSBP7TQTJW~com~hashbangind~shipment/CloudLogs/StoreUUID+, NSUnderlyingError=0x170245580 "The operation couldn’t be completed. Bad file descriptor"}
2013-11-18 21:09:30.451 Shipment[476:1403] UbiquityStoreManager:     - Context   : /private/var/mobile/Library/Mobile Documents/FSBP7TQTJW~com~hashbangind~shipment/CloudLogs/StoreUUID+
2013-11-18 21:09:30.452 Shipment[476:1403] UbiquityStoreManager:     - Underlying: Error Domain=NSPOSIXErrorDomain Code=9 "The operation couldn’t be completed. Bad file descriptor"
2013-11-18 21:09:30.452 Shipment[476:1403] UbiquityStoreManager: Successfully loaded cloud store.
2013-11-18 21:09:30.454 Shipment[476:1403] UbiquityStoreManager: Finished loading cloud store (UbiquityStoreErrorCauseNoError).  Notifying application to refresh its UI.
2013-11-18 21:09:30.456 Shipment[476:1403] shipments: (
)
2013-11-18 21:09:30.825 Shipment[476:4507] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  mobile~128B970C-34E8-44A1-A5B2-5CB304F76A79:2407DB7B-A1F7-4521-80C9-3418DD5E989E
Using local storage: 0

I then tried deleting everything off of both the Mac and iOS and deleting data from iCloud.
Waited 10 minutes to make sure the data synced.
As Apple suggests, I double checked in ~/Library/Mobile Documents/ to make sure it was empty (all that was left was an empty Documents folder)
I also checked https://developer.icloud.com/ and made sure my app didn't show up there.

I then tried opening the iOS app first and I got the following logs:

2013-11-18 21:44:40.715 Shipment[543:60b] [HockeySDK] WARNING: Detecting crashes is NOT enabled due to running the app with a debugger attached.
2013-11-18 21:44:40.818 Shipment[543:60b] Core Data KVS Sync
2013-11-18 21:44:40.818 Shipment[543:1403] UbiquityStoreManager: Loading store...
2013-11-18 21:44:40.818 Shipment[543:1403] UbiquityStoreManager: Will load local store.
2013-11-18 21:44:40.841 Shipment[543:1403] UbiquityStoreManager: Clearing stores...
2013-11-18 21:44:40.842 Shipment[543:1403] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-18 21:44:40.908 Shipment[543:60b]  INFO: Reveal server started.
2013-11-18 21:44:41.096 Shipment[543:1403] UbiquityStoreManager: Loading store: UbiquityStore.sqlite
2013-11-18 21:44:41.155 Shipment[543:1403] UbiquityStoreManager: Successfully loaded local store.
2013-11-18 21:44:41.156 Shipment[543:1403] UbiquityStoreManager: Switching cloud disabled -> enabled
2013-11-18 21:44:41.157 Shipment[543:1403] UbiquityStoreManager: Reloading store...
2013-11-18 21:44:41.157 Shipment[543:1403] UbiquityStoreManager: Will load cloud store.
2013-11-18 21:44:41.158 Shipment[543:1403] UbiquityStoreManager: Clearing stores...
2013-11-18 21:44:41.158 Shipment[543:1403] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-18 21:44:41.755 Shipment[543:1403] UbiquityStoreManager: Loading cloud store: 94302C2E-9A8C-41BB-8C33-3A7462009ECE, v1 (tentative).
2013-11-18 21:44:41.755 Shipment[543:1403] UbiquityStoreManager: [DEBUG] migrationStoreURL: (null)
2013-11-18 21:44:41.756 Shipment[543:1403] UbiquityStoreManager: [DEBUG] migrationStoreOptions: {
    NSInferMappingModelAutomaticallyOption = 1;
    NSMigratePersistentStoresAutomaticallyOption = 1;
    NSReadOnlyPersistentStoreOption = 1;
}
2013-11-18 21:44:41.756 Shipment[543:1403] UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 1
2013-11-18 21:44:41.757 Shipment[543:1403] UbiquityStoreManager: Will migrate to cloud store from: UbiquityStore.sqlite (strategy: 2).
2013-11-18 21:44:41.834 Shipment[543:1403] UbiquityStoreManager: Seeding store (strategy: UbiquityStoreMigrationStrategyIOS): CopyMigrationStore.sqlite -> 94302C2E-9A8C-41BB-8C33-3A7462009ECE.sqlite
2013-11-18 21:44:41.928 Shipment[543:60b] Change Reason: 1
2013-11-18 21:44:41.928 Shipment[543:60b] Changed Key: LastUpdatedDate Value: 406444512.309231
2013-11-18 21:44:41.929 Shipment[543:60b] Changed Key: refreshPaused Value: 0
2013-11-18 21:44:41.963 Shipment[543:1403] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  mobile~1724A51E-4BAA-414F-BAFE-B8AFD60EDD64:94302C2E-9A8C-41BB-8C33-3A7462009ECE
Using local storage: 1
2013-11-18 21:44:41.985 Shipment[543:1403] UbiquityStoreManager: Confirming tentative StoreUUID: 94302C2E-9A8C-41BB-8C33-3A7462009ECE
2013-11-18 21:44:42.046 Shipment[543:1403] UbiquityStoreManager: Writing new StoreUUID:94302C2E-9A8C-41BB-8C33-3A7462009ECE to StoreUUID+ (v1).
2013-11-18 21:44:42.195 Shipment[543:1403] UbiquityStoreManager: Successfully loaded cloud store.
2013-11-18 21:44:42.197 Shipment[543:1403] UbiquityStoreManager: Finished loading cloud store (UbiquityStoreErrorCauseNoError).  Notifying application to refresh its UI.
2013-11-18 21:44:42.199 Shipment[543:1403] shipments: (
)
2013-11-18 21:44:42.593 Shipment[543:4707] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  mobile~1724A51E-4BAA-414F-BAFE-B8AFD60EDD64:94302C2E-9A8C-41BB-8C33-3A7462009ECE
Using local storage: 0
2013-11-18 21:44:46.602 Shipment[543:6b07] UbiquityStoreManager: Handling cloud deletion.
2013-11-18 21:44:46.604 Shipment[543:6b07] UbiquityStoreManager: Recovering from cloud deletion.  Falling back to local store.
2013-11-18 21:44:46.605 Shipment[543:6b07] UbiquityStoreManager: Clearing stores...
2013-11-18 21:44:46.607 Shipment[543:6b07] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-18 21:44:46.608 Shipment[543:4707] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  mobile~1724A51E-4BAA-414F-BAFE-B8AFD60EDD64:94302C2E-9A8C-41BB-8C33-3A7462009ECE
Using local storage: 1
2013-11-18 21:44:47.471 Shipment[543:6b07] UbiquityStoreManager: Switching cloud enabled -> disabled
2013-11-18 21:44:47.472 Shipment[543:6b07] UbiquityStoreManager: Loading store...
2013-11-18 21:44:47.472 Shipment[543:6b07] UbiquityStoreManager: Will load local store.
2013-11-18 21:44:47.472 Shipment[543:6b07] UbiquityStoreManager: Clearing stores...
2013-11-18 21:44:47.473 Shipment[543:6b07] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-18 21:44:47.672 Shipment[543:6b07] UbiquityStoreManager: Loading store: UbiquityStore.sqlite
2013-11-18 21:44:47.677 Shipment[543:6b07] UbiquityStoreManager: Successfully loaded local store.
2013-11-18 21:44:47.678 Shipment[543:6b07] UbiquityStoreManager: Stores will change.  Notifying application to reset its UI.
2013-11-18 21:44:47.679 Shipment[543:4707] -[PFUbiquitySwitchboardEntry containerIdentifierChanged:](508): CoreData: Ubiquity:  <PFUbiquitySwitchboardEntry: 0x1700cce80>: 
    localPeerID: mobile~1724A51E-4BAA-414F-BAFE-B8AFD60EDD64
    ubiquityRootURL: <PFUbiquityLocation: 0x1700b3860>: /var/mobile/Library/Mobile Documents/FSBP7TQTJW~com~hashbangind~shipment/CloudLogs/94302C2E-9A8C-41BB-8C33-3A7462009ECE
    registeredCoordinators: {
    "94302C2E-9A8C-41BB-8C33-3A7462009ECE" = "{(\n)}";
}

Error adding store for new account: Error Domain=NSCocoaErrorDomain Code=134080 "(null) is not a valid file URL" UserInfo=0x178278100 {NSLocalizedDescription=(null) is not a valid file URL}

I closed the app and relaunched and that time it launched fine and the logs looked fine.
So I then went to the Mac app, launched it and added new data.
Waited a while to give time for syncing and then went back to the iOS app.
Here it looks like it started up fine but no data was pulled down from iCloud
The logs from that last run (where data should have shown but doesnt) are:

2013-11-18 22:06:08.822 Shipment[581:60b] [HockeySDK] WARNING: Detecting crashes is NOT enabled due to running the app with a debugger attached.
2013-11-18 22:06:08.924 Shipment[581:60b] Core Data KVS Sync
2013-11-18 22:06:08.925 Shipment[581:1403] UbiquityStoreManager: Loading store...
2013-11-18 22:06:08.925 Shipment[581:1403] UbiquityStoreManager: Will load cloud store.
2013-11-18 22:06:08.945 Shipment[581:1403] UbiquityStoreManager: Clearing stores...
2013-11-18 22:06:08.945 Shipment[581:1403] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-18 22:06:09.009 Shipment[581:60b]  INFO: Reveal server started.
2013-11-18 22:06:09.537 Shipment[581:1403] UbiquityStoreManager: Loading cloud store: 94302C2E-9A8C-41BB-8C33-3A7462009ECE, v1 (definite).
2013-11-18 22:06:09.538 Shipment[581:1403] UbiquityStoreManager: [DEBUG] migrationStoreURL: (null)
2013-11-18 22:06:09.539 Shipment[581:1403] UbiquityStoreManager: [DEBUG] migrationStoreOptions: {
    NSInferMappingModelAutomaticallyOption = 1;
    NSMigratePersistentStoresAutomaticallyOption = 1;
    NSReadOnlyPersistentStoreOption = 1;
}
2013-11-18 22:06:09.605 Shipment[581:1403] UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 0
2013-11-18 22:06:09.673 Shipment[581:1403] UbiquityStoreManager: [DEBUG] Will NOT migrate to cloud store from: UbiquityStore.sqlite (strategy: 2).
2013-11-18 22:06:09.708 Shipment[581:1403] UbiquityStoreManager: Loading store: 94302C2E-9A8C-41BB-8C33-3A7462009ECE.sqlite
2013-11-18 22:06:09.733 Shipment[581:1403] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  mobile~1724A51E-4BAA-414F-BAFE-B8AFD60EDD64:94302C2E-9A8C-41BB-8C33-3A7462009ECE
Using local storage: 1
2013-11-18 22:06:09.835 Shipment[581:1403] UbiquityStoreManager: Successfully loaded cloud store.
2013-11-18 22:06:09.836 Shipment[581:1403] UbiquityStoreManager: Finished loading cloud store (UbiquityStoreErrorCauseNoError).  Notifying application to refresh its UI.
2013-11-18 22:06:09.839 Shipment[581:1403] shipments: (
)
2013-11-18 22:06:40.957 Shipment[581:4707] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  mobile~1724A51E-4BAA-414F-BAFE-B8AFD60EDD64:94302C2E-9A8C-41BB-8C33-3A7462009ECE
Using local storage: 0

[ManagedObjectContext release] message sent to deallocated instance...

Sometimes I get this error when iCloud is turned on, here's the log:

2014-01-31 09:33:34.549 iSteccone[31431:6a0f] Log Successfully loaded cloud store.
2014-01-31 09:33:34.550 iSteccone[31431:6a0f] Log Switching cloud enabled -> enabled
2014-01-31 09:33:34.550 iSteccone[31431:6a0f] Log Reloading store...
2014-01-31 09:33:34.550 iSteccone[31431:6a0f] Log Will load cloud store.
2014-01-31 09:33:34.550 iSteccone[31431:6a0f] Log Clearing stores...
2014-01-31 09:33:34.550 iSteccone[31431:6a0f] Log Will clear stores. Notifying application to reset its UI.
2014-01-31 09:33:34.550 iSteccone[31431:70b] *** -[NSManagedObjectContext release]: message sent to deallocated instance 0xe8bf530

Where am I wrong?

More Question Then Issue

So I have submitted a DTS to Apple but of course they are "off for the holiday" from the 22nd until the 2nd.... BARF

I was looking through my logs again and from how I read the following it makes it seem like the logs here are telling us that its not syncing.
Let me explain...

UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 0
UbiquityStoreManager: [DEBUG] Will NOT migrate to cloud store from: UbiquityStore.sqlite (strategy: 2).
UbiquityStoreManager: Loading store: 41FA9583-8968-44AD-B43D-2026730DD408.sqlite
-[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](760): CoreData: Ubiquity:  dallas~351A8D7D-3AC4-5210-B2A4-4C2FDAFE13D1:41FA9583-8968-44AD-B43D-2026730DD408
Using local storage: 1

So it says its not safe for seeding, then says it will NOT migrate to the cloud store and instead loads the local storage

Am I not reading this right?

Yes thats just an excerpt.
Full log is below

2013-11-22 02:13:33.117 Shipment[26121:300f] UbiquityStoreManager: Loading store...
2013-11-22 02:13:33.118 Shipment[26121:300f] UbiquityStoreManager: Will load local store.
2013-11-22 02:13:33.118 Shipment[26121:300f] UbiquityStoreManager: Clearing stores...
2013-11-22 02:13:33.119 Shipment[26121:300f] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-22 02:13:33.173 Shipment[26121:300f] UbiquityStoreManager: Loading store: UbiquityStore.sqlite
2013-11-22 02:13:33.178 Shipment[26121:300f] UbiquityStoreManager: Successfully loaded local store.
2013-11-22 02:13:33.179 Shipment[26121:300f] UbiquityStoreManager: Switching cloud disabled -> enabled
2013-11-22 02:13:33.179 Shipment[26121:300f] UbiquityStoreManager: Reloading store...
2013-11-22 02:13:33.179 Shipment[26121:300f] UbiquityStoreManager: Will load cloud store.
2013-11-22 02:13:33.179 Shipment[26121:300f] UbiquityStoreManager: Clearing stores...
2013-11-22 02:13:33.180 Shipment[26121:300f] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2013-11-22 02:13:33:181 Shipment[26121:303] App, Launch, , 
2013-11-22 02:13:33.272 Shipment[26121:303] Core Data KVS Sync
2013-11-22 02:13:33.298 Shipment[26121:300f] UbiquityStoreManager: Loading cloud store: 41FA9583-8968-44AD-B43D-2026730DD408, v1 (definite).
2013-11-22 02:13:33.299 Shipment[26121:300f] UbiquityStoreManager: [DEBUG] migrationStoreURL: (null)
2013-11-22 02:13:33.299 Shipment[26121:300f] UbiquityStoreManager: [DEBUG] migrationStoreOptions: {
    NSInferMappingModelAutomaticallyOption = 1;
    NSMigratePersistentStoresAutomaticallyOption = 1;
    NSReadOnlyPersistentStoreOption = 1;
}
2013-11-22 02:13:33.322 Shipment[26121:300f] UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 0
2013-11-22 02:13:33.351 Shipment[26121:300f] UbiquityStoreManager: [DEBUG] Will NOT migrate to cloud store from: UbiquityStore.sqlite (strategy: 2).
2013-11-22 02:13:33.361 Shipment[26121:300f] UbiquityStoreManager: Loading store: 41FA9583-8968-44AD-B43D-2026730DD408.sqlite
2013-11-22 02:13:33.390 Shipment[26121:300f] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](760): CoreData: Ubiquity:  dallas~351A8D7D-3AC4-5210-B2A4-4C2FDAFE13D1:41FA9583-8968-44AD-B43D-2026730DD408
Using local storage: 1
2013-11-22 02:13:33.436 Shipment[26121:300f] UbiquityStoreManager: Successfully loaded cloud store.
2013-11-22 02:13:33.437 Shipment[26121:300f] UbiquityStoreManager: Finished loading cloud store (UbiquityStoreErrorCauseNoError).  Notifying application to refresh its UI.
2013-11-22 02:13:33.438 Shipment[26121:300f] Refreshing All UI
2013-11-22 02:13:33.560 Shipment[26121:300f] UbiquityStoreManager: Stores will change.  Notifying application to reset its UI.
2013-11-22 02:13:33.570 Shipment[26121:300f] UbiquityStoreManager: Stores changed (UbiquityStoreErrorCauseNoError).  Notifying application to refresh its UI.
2013-11-22 02:13:33.570 Shipment[26121:2307] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](760): CoreData: Ubiquity:  dallas~351A8D7D-3AC4-5210-B2A4-4C2FDAFE13D1:41FA9583-8968-44AD-B43D-2026730DD408
Using local storage: 0
2013-11-22 02:13:33.574 Shipment[26121:300f] Refreshing All UI

CocoaPods version tag out of date.

I love this library and I am using cocoa pods to include it in my project, however the only version tagged is 0.1.0 which is 8 months old.

Could you please update the version tag so that I can include all the awesome updates available in the current version?

Thanks

Store always switches to Cloud Store without intervention

After pulling the latest two changes, my Store always switches to cloud store without any intervention.

Log on first launch after pulling the latest changes:
2013-12-11 16:26:04.769 Diabetes Pal[8829:2307] UbiquityStoreManager: Loading store...
2013-12-11 16:26:04.771 Diabetes Pal[8829:2307] UbiquityStoreManager: Will load local store.
2013-12-11 16:26:04.771 Diabetes Pal[8829:2307] UbiquityStoreManager: Clearing stores...
2013-12-11 16:26:04.771 Diabetes Pal[8829:2307] UbiquityStoreManager: Will clear stores. Notifying application to reset its UI.
2013-12-11 16:26:04.919 Diabetes Pal[8829:2307] UbiquityStoreManager: Loading store: UbiquityStore.sqlite
2013-12-11 16:26:04.930 Diabetes Pal[8829:2307] UbiquityStoreManager: Successfully loaded local store.
2013-12-11 16:26:04.931 Diabetes Pal[8829:2307] UbiquityStoreManager: Finished loading local store (UbiquityStoreErrorCauseNoError). Notifying application to refresh its UI.
2013-12-11 16:26:05.002 Diabetes Pal[8829:2307] Cloud Store: file:///Users/freiburg/Library/Containers/com.lobotomo.diabetespalosx/Data/Library/Application%20Support/com.lobotomo.diabetespalosx/CloudStore/FFF3DA9A-9A5B-4BA1-9769-5D1FF838548E.sqlite

==> He seem to load the local store and the data that is displayed in my app is clearly also from the local store file. BUT when I query the cloudEnabled property, I get a status that the cloud store is enabled.

On second launch of the app, the cloud store is then loaded:
2013-12-11 16:28:05.572 Diabetes Pal[8879:6103] UbiquityStoreManager: Loading store...
2013-12-11 16:28:05.572 Diabetes Pal[8879:6103] UbiquityStoreManager: Will load cloud store.
2013-12-11 16:28:05.572 Diabetes Pal[8879:6103] UbiquityStoreManager: Clearing stores...
2013-12-11 16:28:05.573 Diabetes Pal[8879:6103] UbiquityStoreManager: Will clear stores. Notifying application to reset its UI.
2013-12-11 16:28:05.856 Diabetes Pal[8879:6103] UbiquityStoreManager: Loading cloud store: FFF3DA9A-9A5B-4BA1-9769-5D1FF838548E, v1 (definite).
2013-12-11 16:28:05.856 Diabetes Pal[8879:6103] UbiquityStoreManager: [DEBUG] migrationStoreURL: (null)
2013-12-11 16:28:05.856 Diabetes Pal[8879:6103] UbiquityStoreManager: [DEBUG] migrationStoreOptions: {
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
NSReadOnlyPersistentStoreOption = 1;
}
2013-12-11 16:28:05.895 Diabetes Pal[8879:6103] UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 0
2013-12-11 16:28:05.960 Diabetes Pal[8879:6103] UbiquityStoreManager: [DEBUG] Will NOT migrate to cloud store from: UbiquityStore.sqlite (strategy: 2).
2013-12-11 16:28:05.981 Diabetes Pal[8879:6103] UbiquityStoreManager: Loading store: FFF3DA9A-9A5B-4BA1-9769-5D1FF838548E.sqlite
2013-12-11 16:28:05.999 Diabetes Pal[8879:6103] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: freiburg43948A8D-10AC-5B12-A998-DF8AEED1AC20:FFF3DA9A-9A5B-4BA1-9769-5D1FF838548E
Using local storage: 1
2013-12-11 16:28:06.183 Diabetes Pal[8879:6103] UbiquityStoreManager: Successfully loaded cloud store.
2013-12-11 16:28:06.184 Diabetes Pal[8879:6103] UbiquityStoreManager: Finished loading cloud store (UbiquityStoreErrorCauseNoError). Notifying application to refresh its UI.
2013-12-11 16:28:06.230 Diabetes Pal[8879:6103] Cloud Store: file:///Users/freiburg/Library/Containers/com.lobotomo.diabetespalosx/Data/Library/Application%20Support/com.lobotomo.diabetespalosx/CloudStore/FFF3DA9A-9A5B-4BA1-9769-5D1FF838548E.sqlite
2013-12-11 16:28:07.207 Diabetes Pal[8879:6103] UbiquityStoreManager: Stores will change. Notifying application to reset its UI.
2013-12-11 16:28:07.240 Diabetes Pal[8879:6103] UbiquityStoreManager: Stores changed (UbiquityStoreErrorCauseNoError). Notifying application to refresh its UI.
2013-12-11 16:28:07.242 Diabetes Pal[8879:5903] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: freiburg
43948A8D-10AC-5B12-A998-DF8AEED1AC20:FFF3DA9A-9A5B-4BA1-9769-5D1FF838548E
Using local storage: 0
2013-12-11 16:28:07.272 Diabetes Pal[8879:6103] Cloud Store: file:///Users/freiburg/Library/Containers/com.lobotomo.diabetespalosx/Data/Library/Application%20Support/com.lobotomo.diabetespalosx/CloudStore/FFF3DA9A-9A5B-4BA1-9769-5D1FF838548E.sqlite

==> He loads the cloud store. I can switch back and I will see the local store again, but cloudEnabled still stays YES

Reverting your last two changes fixes the issue again.

Example for 2 Stores

Hi

I am intending to use several stores in my application. They all use the same datamodel but the data I fill into these stores is completely different. All should be synced to iCloud or not, depending on the setting.

How am I supposed to do this with USM? I have tried storeName and storeConfiguration but they have no effect.

Example project is dead

Really awesome job...

But, the example project.
Can't compile.
The xcdatamodel seemed corrupted from a commit about 3 months ago.

please fix it.

Need to create (local) snapshots

Is this possible:

  1. snapshot the local store and then upload it to a save place
  2. download it back, swap the local store with it and then rebuild iCloud from the local store?

I need a way to enable my users to keep snapshots over a long time. I have a complex data model and therefor exporting and importing the data using a custom file format is no solution to me. The complexity would be to high, esp. with schema changes.

Fallback Store Not Working

According to the WWDC 2013 iCloud video (session 207) when the user can not access the cloud (say iCloud is having issues or they are offline) the Fallback Store should allow them to access the data that is stored locally from the last time they downloaded, and they can access that data, and even make changes to it, and when a connection comes back it will push up the changes.

The problem I am having is that if I disconnect from the internet then I do not get access to any of the data. It looks like I have no data.

In the 2013 video it says that Apple is taking control of handling the fallback store, so I am not sure if maybe you still have code from when they weren't handling it, or something???

For example it must now be stored in local storage and not in iCloud (in the app sandboxed is sandboxed)

UbiquityStoreManager + Magical Record

Hi! I use MagicalRecord in my project, but icloud support not good.
I want to use your manager with MagicalRecord, but when i run my app on two devices i have different data. But icloud container is joint. Can you help me with my problem? Or can you make some tutorial for working with your code + MagicalRecord?

ManagedObjectContext slow loading

Using my app with iCloud enabled i get the following error

+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name....

I have to wait about 10 seconds before the ManagedObjectContext is loaded so do not get the error above.

Is there a way to avoid the error and allow the user to display data?

Is the LGPLv3 compatible with the App Store at all?

I know that LGPLv2 is controversial at best, lots of people say it's simply incompatible, others say that it's ok if you provide the object files for download. In general, this license is a huge PITA to work with. Is there any difference with v3? What about the Anti-DRM clauses added there?

deleteCloudContainerLocalOnly:YES Deletes All Devices

I ran [self.ubiquityStoreManager deleteCloudContainerLocalOnly:YES]; on my Mac app expecting to only delete the contents of that device, however instead it deleted the contents on all devices, just as if I had specified NO instead of YES

Please add semantic version tags

I’ve recently added UbiquityStoreManager to the CocoaPods package manager repo.

CocoaPods is a tool for managing dependencies for OS X and iOS Xcode projects and provides a central repository for iOS/OS X libraries. This makes adding libraries to a project and updating them extremely easy and it will help users to resolve dependencies of the libraries they use.

However, UbiquityStoreManager doesn't have any version tags. I’ve added the current HEAD as version 0.0.1, but a version tag will make dependency resolution much easier.

Semantic version tags (instead of plain commit hashes/revisions) allow for resolution of cross-dependencies.

In case you didn’t know this yet; you can tag the current HEAD as, for instance, version 1.0.0, like so:

$ git tag -a 1.0.0 -m "Tag release 1.0.0"
$ git push --tags

Getting an optimistic locking failure

I'm trying to use the UbiquityStoreManager. I've installed my app in the simulator and on a device. After editing objects on the device, I get the following crash error now after each start of the app.

2014-02-07 22:10:31:273 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Loading store...
2014-02-07 22:10:31:273 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Will load cloud store.
2014-02-07 22:10:31:274 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Clearing stores...
2014-02-07 22:10:31:274 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Will clear stores.  Notifying application to reset its UI.
2014-02-07 22:10:31:315 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Loading cloud store: 1DA646F2-BC01-47A9-AF10-C9927BF675A2, v1 (definite).
2014-02-07 22:10:31:316 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: [DEBUG] migrationStoreURL: (null)
2014-02-07 22:10:31:316 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: [DEBUG] migrationStoreOptions: {
    NSInferMappingModelAutomaticallyOption = 1;
    NSMigratePersistentStoresAutomaticallyOption = 1;
    NSReadOnlyPersistentStoreOption = 1;
}
2014-02-07 22:10:31:322 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: [DEBUG] cloudSafeForSeeding: 0
2014-02-07 22:10:31:326 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: [DEBUG] Will NOT migrate to cloud store from: MyAppUbiquityStore.sqlite (strategy: 2).
2014-02-07 22:10:31:329 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Loading store: 1DA646F2-BC01-47A9-AF10-C9927BF675A2.sqlite
2014-02-07 22:10:31.344 MyApp[59621:1303] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  AZau~sim08080FB0-40C3-503D-9CE4-B15138E48D42:1DA646F2-BC01-47A9-AF10-C9927BF675A2
Using local storage: 1
2014-02-07 22:10:31:359 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Successfully loaded cloud store.
2014-02-07 22:10:31:360 MyApp[59621:4867] -[UbiquityStoreManager log:] [Line 555] UbiquityStoreManager: Finished loading cloud store (UbiquityStoreErrorCauseNoError).  Notifying application to refresh its UI.
2014-02-07 22:10:31.415 MyApp[59621:3507] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](754): CoreData: Ubiquity:  AZau~sim08080FB0-40C3-503D-9CE4-B15138E48D42:1DA646F2-BC01-47A9-AF10-C9927BF675A2
Using local storage: 0
2014-02-07 22:10:31.924 MyApp[59621:1303] CoreData: warning: An NSManagedObjectContext delegate overrode fault handling behavior to silently delete the object with ID '0x136716a0 <x-coredata://6AE50E77-A609-4D06-810C-9F785E27A08B/Flower/p358>' and substitute nil/0 for all property values instead of throwing.
Description of exception being thrown: 'optimistic locking failure'

What's the cause of this? This is my merge policy setting:

- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager didLoadStoreForCoordinator:(NSPersistentStoreCoordinator *)coordinator
                     isCloud:(BOOL)isCloudStore
{
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    moc.persistentStoreCoordinator = coordinator;
    moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
    _managedObjectContext = moc;
}

Question - What is the recommended approach for migrating in Ordered Sets

I believe that iCloud doesn't support ordered sets. If I am using USM to migrate to using iCloud how do you suggest I handle them?

Do I need to initially migrate to a structure that replaces them and then activate iCloud using USM?

Sorry to ask here but I'm hoping that a quick answer from you will save me hours of experimenting and then it will be documented for other developers too.

Thanks!

exception with the last commit(s)

2013-05-10 09:38:39.026 AppNameHere[8668:907] UbiquityStoreManager: (Re)loading store...
2013-05-10 09:38:39.092 AppNameHere[8668:1603] -[NSURL downloadAndWait]: unrecognized selector sent to instance 0x1f85a350
2013-05-10 09:40:19.789 AppNameHere[8668:1603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURL downloadAndWait]: unrecognized selector sent to instance 0x1f85a350'
*** First throw call stack:
(0x3129e2a3 0x3914297f 0x312a1e07 0x312a0531 0x311f7f68 0xcb5e7 0xcbbd5 0xc29a9 0xc25b5 0x31b33d41 0x31b2b5c1 0x31ba3be3 0x3955a11f 0x3955e961 0x3955eac1 0x3958ea11 0x3958e8a4)
libc++abi.dylib: terminate called throwing an exception
error

Persistent Store iCloud Backup Option?

Forgive me if I've missed it anywhere in the documentation, but is there anything present for disabling backups for the persistent store? I'm using external storage and have ~200MB of data so far in testing, which is getting backed up to iCloud. I know it's a permissions flag that gets set on the files but since UBM is technically managing that data, it seems fitting that it should be capable of setting the "no backup" flags as necessary.

Thoughts? I can certainly work around it, it just seemed like something that would fit in USM :)

Note: I haven't started using iCloud sync yet, I'm just using USM locally for the time-being but will begin testing sync support very soon.

Slow loading even with iCloud disabled

Hey,

I've instantiated UbiquityStoreManager and set cloudEnabled: inside application: didFinishLaunchingWithOptions:. The problem is the slow loading of data every time the app is opened, even if iCloud is disabled. Am I doing something wrong or missing some setting?

static Framework

are you planning on adding support for building and bundling a static framework so the project can be added in a "clean" way?

Use UBM for local data

I'm developing an application that stores data with CoreData, the initial release should only use local data and no iCloud but in a near future (when the iPad version will be available) it will.

The question is: can I use USM for local data until the iCloud sync is implemented? There is cloudEnabled property, but it can be helpful?

Best practice for keeping strong refs to NSManagedObjects

I'm currently looking to implement iCloud sync in an existing application that has, up until this point, passed around an instance of my main NSManagedObjectContext to various controllers and models.

Given that the UbiquityStoreManager documentation warns that my main MOC could become unavailable at any time, I've taken steps to instead refer to my AppDelegate's MOC property and to fail gracefully if it is unavailable. That seems clear, however I'm confused as to best practice when referencing NSManagedObjects.

As a basic example: I pass NSManagedObject references to my detail view controllers for editing purposes. I'm aware that it's generally a bad idea to shift NSManagedObjects between NSManagedObjectContexts, so what's the best way of handling this? Should I be looking up the NSManagedObject via it's objectID in the current main MOC each time I try to access it within the detail view?

Use existing iCloud store

Hi,
I don't understand how to use an existing iCloud store created by "device A" into "device B" after user have "switched on" on "device B",
can you explain me with a little example?

Thanks in advance

Compile error

Hello,

the following compile error occurs:

No visible @interface for UbiquityStoreManager declares the selector initStoreNamed...

// STEP 1 - Initialize the UbiquityStoreManager
_ubiquityStoreManager = [[UbiquityStoreManager alloc] initStoreNamed:nil withManagedObjectModel:nil
localStoreURL:nil containerIdentifier:nil additionalStoreOptions:nil
delegate:self];

Best regards
Arno

Typo in tryLoadCloudStore and tryLoadLocalStore

Hello!
Just stumbled across (what I think would be) a type in the aforementioned methods.
Shouldn't the lines
"// Make sure the store is still missing.
if (![[psc persistentStores] count])
return;"
in both methods read
"// Make sure the store is still missing.
if ([[psc persistentStores] count])
return;"?
Without '!'??
Greetings
LaborEtArs

PS: I'm totally new to GitHub. If I did a massive mistake by opening an 'issue' for this or did any other dumb thing, just give me a note :-)

Infinite Loop when iCloud not setup?

When I reset my simulator or device and do not setup iCloud, when I run I seem to be getting an infinite loop USM with

Loading store...
Will load local store.
Clearing stores...
Will clear stores.  Notifying application to reset its UI.
Switching cloud disabled -> enabled
Loading store...
Cannot load cloud store: User is not logged into iCloud.  Falling back to local store.

Then it just keeps looping from that top "Will Load..." down those others and again, until it finally crashes.
Both simulator and device, both 32bit and 64bit, clean install of device even.

Screen shot of Xcode below and links to the logs and to the full list of the thread debug contents of the USM thread from Xcode on the shown crash.

screen shot 2013-12-07 at 2 15 55 pm

Processing before didImportChanges: merges and saves

My project has two core data models, one that is iCloud synched, and the other which is local only, both in the same context. I need to update some things in the local only model when data changes in iCloud model.

In looking at the following from UbiquityStoreManager.m it looks like I would not get the USMStoreDidImportChangesNotification until after deleted managed objects were already removed from the persistent store?

- (void)didImportChanges:(NSNotification *)note {

    NSManagedObjectContext *moc = nil;
    if ([self.delegate respondsToSelector:@selector(managedObjectContextForUbiquityChangesInManager:)])
        moc = [self.delegate managedObjectContextForUbiquityChangesInManager:self];
    if (moc) {
        [self log:@"Importing ubiquity changes into application's MOC.  Changes:\n%@", note.userInfo];
        [moc performBlockAndWait:^{
            [moc mergeChangesFromContextDidSaveNotification:note];

            NSError *error = nil;
            if ([moc hasChanges] && ![moc save:&error]) {
                [self error:error cause:UbiquityStoreErrorCauseImportChanges context:note];
                [self reloadStore];
                return;
            }
        }];
    }
    else
        [self log:@"Application did not specify an import MOC, not importing ubiquity changes:\n%@", note.userInfo];

    dispatch_async( dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:USMStoreDidImportChangesNotification
                                                            object:self userInfo:[note userInfo]];
    } );
}

If I register for NSPersistentStoreDidImportUbiquitousContentChangesNotification directly how do I know that I received this notifications before UbiquityStoreManager has merged the changes and saved?

Is it possible to get a delegate call at the beginning of didImportChanges:. Something like:

    if ([self.delegate respondsToSelector:@selector(willMergeAndSaveImportChangesFromNote:)])
        [self.delegate willMergeAndSaveImportChangesFromNote:note];

This way I can save what I need to process from the notifications, multithreaded aware, for later processing before the data goes away or changes.

Thank you.
Neil

Ubiquity changes not imported after store reload

I am very happy with your code. But I have one problem: when data changes on one device the notification is thrown. But how to populate? I have registered the UbiquityManagedStoreDidImportChangesNotification also to reloadFetchedResults.

I think that I always get the old managedObjectContext from managedObjectContextForUbiquityChangesInManager

To be clear, when I start the app again the new data is shown. Syncing does work, I have no errors. The logs are fine. But I cannot populate.

Never gets MOC

My application uses many entities. The primary table is not a good place to put the iCloud switch. It uses a split view on the iPad with a search box. I tried to put a view in the table with the iCloud switch and clear/rebuild buttons along with a search box but that caused problems with the search box. So I also have a settings entity and settings screen where I included the iCloud switch and buttons.

I don't know if this is part of the problem or not. I did add the code shown in your MasterViewController to my split screen MasterViewController for the fetchedresultscontroller and the insertnewobject changing 'Event' to the entity that belongs to my MasterViewController. I also added that code to my SettingsViewController where the iCloud switch is located.

The problem is, the MOC never gets initialized. Here is what shows up in the debug window:

2013-12-08 06:45:22.312 Customer Manager[1098:60b] Starting UbiquityStoreManagerExample on device: Peggy's iPad

2013-12-08 06:45:22.338 Customer Manager[1098:1603] UbiquityStoreManager: Loading store...
2013-12-08 06:45:22.339 Customer Manager[1098:1603] UbiquityStoreManager: Will load local store.
2013-12-08 06:45:22.340 Customer Manager[1098:1603] UbiquityStoreManager: Clearing stores...
2013-12-08 06:45:22.340 Customer Manager[1098:1603] UbiquityStoreManager: Will clear stores. Notifying application to reset its UI.
2013-12-08 06:45:22.450 Customer Manager[1098:1603] UbiquityStoreManager: Loading store: CMDataModel.sqlite
2013-12-08 06:45:22.461 Customer Manager[1098:1603] UbiquityStoreManager: Successfully loaded local store.
2013-12-08 06:45:22.462 Customer Manager[1098:1603] UbiquityStoreManager: Finished loading local store (UbiquityStoreErrorCauseNoError). Notifying application to refresh its UI.
2013-12-08 06:45:22.615 Customer Manager[1098:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An instance of NSFetchedResultsController requires a non-nil fetchRequest and managedObjectContext'
*** First throw call stack:
(0x18d5e709c 0x19991dd78 0x18d2f56ac 0x100123a4c 0x100122568 0x19059bbd8 0x19059baf8 0x19059b888 0x19059f754 0x19059f25c 0x1001214b4 0x199eec420 0x199eec3e0 0x199eef56c 0x18d5a6d64 0x18d5a50a4 0x18d4e5b38 0x192eb7830 0x1905240e8 0x100144b9c 0x199f07aa0)
libc++abi.dylib: terminating with uncaught exception of type NSException

I've tried stepping through the code and it appears that the MOC is being initialized on a different thread than the MasterViewController code. I've tried putting in a While claus where the fetchedresultscontoller is initialized in the MasterViewController to see if a wait can give the MOC time to initialize but that just causes the application to eventually terminate probably because the MOC never gets initialized and things timeout.

Any idea why the MOC never gets initialized and how to fix that? I'd really like to implement iCloud in my application because I have both iPad and iPhone versions and plan to also write an OS X version. My iPad/iPhone versions are specifically set up for iOS 7.

Bob

Internet Connection and server side entities

Question 1 :i want to know why failedLoadingStoreWithCause don't fire when no internet connection and willLoadStoreIsCloud still call to try to connect. when to stop ?

Question 2 : can i get the server side entities before cached in core data to perform some operations on it.

Thanks

MOC - Best Practises?

We are about to release an update to our application, the main change was to migrate from the ALEKSEYN iCloudStoreManager to your UbiquityStoreManager. And it was a painless integration - thanks for the efforts!

We have implemented the setup as per the documentation (and can be seen here: #2 (comment) ).

We have only found one issue (just before launch), which is caused by good old Apple/iCloud bugs..

The setup:

  1. Run the identical Application Build on multiple devices - 2 iPhones and an iPad.
  2. Add Data from a Device - it Appears in the other devices.
  3. Update the data on same device - data updates on other devices.
  4. Wait an hour, but leave apps open. Edit the new record on another device - all devices go nutty (data mismatching, etc).
  5. We are running the latest build (and use every build inbetween).
  6. We also tried to update the Stale Interval... _managedObjectContext.stalenessInterval = 0.0f;

We had this issue with the old Library, and the only work around was to force reset the MOC and Parent after every update Notification:
[[[[myAppDelegate appDelegate] managedObjectContext] parentContext] reset];
[[[myAppDelegate appDelegate] managedObjectContext] reset];

However, this does not appear to work with this library. The reset does appear to help, but seems like the MOC becomes disjointed. I believe this is not really a suitable fix.

The only real way to get the data working 100% is to ensure the one device is running the application, and all other devices have force-quit (running in background does not reload the store when reopen).

The CoreData testing I am doing is a single table with no linkages. So bare bones with two text fields.

I am aware that bug tracking is not really applicable here, so the questions are:

  1. Should the standard set up (as per the example/readme) have this issue - where data is updated on two devices (at separate intervals, without a relauch of the app) becomes disjointed?
  2. What is the best way to "reset"/"reload" the Store? Would forcing a reloadStore be better?
  3. Should we reloadStore when the App returns to the foreground?

If there is any additional info I can provide, let me know. Unfortunately, I am unable to easily get the code out...

storeConfiguration Parameter is an id type?

Did you really mean to use the id type for the storeConfiguration parameter?

If so, I'm curious why?

- (id)initStoreNamed:(NSString *)contentName withManagedObjectModel:(NSManagedObjectModel *)model localStoreURL:(NSURL *)localStoreURL
 containerIdentifier:(NSString *)containerIdentifier storeConfiguration:storeConfiguration storeOptions:(NSDictionary *)storeOptions
            delegate:(id<UbiquityStoreManagerDelegate>)delegate {

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.