Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite to simplify things #11

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open

Conversation

lhunath
Copy link
Contributor

@lhunath lhunath commented Jan 25, 2013

I've rewritten the manager almost entirely taking into account all of iOS 6's new iCloud API.

Major improvements are:

  • More consistent and transparent code
  • Removed anything that didn't belong there
  • Simplified the use of the manager as much as possible
  • Minimized the public API of the manager
  • Hopefully carefully handled all the dodgy cases
  • Detecting user account changes or user deletion of the local container

lhunath added 30 commits May 27, 2012 14:21
[FIXED]     If the PSC's stores disappear, make sure to re-open them.
[FIXED]     While the PSC is loading stores, mark it as not-ready, so the app knows not to use it.
Removed all UI aspects.
Removed localUUID
More consistent naming
Easier to use API
Cleaner, more transparent, more modern and safer code.
Uses (requires) iOS6's additions for working with iCloud.
Handles more edge cases (iCloud account switches, store deletion, etc.)
[FIXED]     Now using a tentativeStoreUUID to store a new random UUID
            that will be assigned to the storeUUID as soon as the store
            has been successfully created or migrated with it.
[IMPROVED]  Small naming improvements to be more consistent with the new API.
[FIXED]     A warning with regards to className not being a known selector.
[FIXED]     Duplicate dot when adding extension sqlite to local store name.
[FIXED]     Don't try to migrate when the cloud store is not tentative (another device created a cloud store already).
[ADDED]     API for applications to test whether it's safe to seed the cloud store (if they wish to do so manually).
[FIXED]     Create the directory for the local store before opening it in case it doesn't exist yet.
[FIXED]     Use a separate queue for observing changes to the store URL.
[IMPROVED]  Better logging in case no store was successfully added.
[FIXED]     Don't confirm tentative UUID when store was not successfully added.
[ADDED]     Some API documentation.
[UPDATED]   Some cleanup.
[FIXED]     Migration safety check should test the right thing, not indirectly.
[UPDATED]   Store reset code consolidated.
[FIXED]     Make sure a new tentative store UUID will be used after resetting the cloud store.
[FIXED]     Save after cloud import to prevent losing changes.  Log errors verbosely.
[ADDED]     Some API documentation.
[UPDATED]   Some cleanup.
[FIXED]     Migration safety check should test the right thing, not indirectly.
[UPDATED]   Store reset code consolidated.
[FIXED]     Make sure a new tentative store UUID will be used after resetting the cloud store.
[FIXED]     Save after cloud import to prevent losing changes.  Log errors verbosely.
[ADDED]     Migration strategies:
                - iOS migration (as before) just uses the PSC's migratePersistentStore.
                - CopyEntities migration attempts to copy all the entities from the source store to the destination and rebuild relationships. (WIP)
                - Manual migration allows the application to do its own migration.
                - None migration does no migration and just loads the existing store or creates an empty one if one doesn't exist.
            This was needed mostly because the iOS migration used before is bugged in iOS 6.1.
[REMOVED]   Direct access to the PSC.  The idea is now that you init your MOC whenever the delegate is triggered for a successful store load.  This means much more reliable and consistent access to the store coordinator and only when the store is ready.
[ADDED]     Delegate method to learn when persistence becomes unavailable (because it's loading a new store).
[ADDED]     Delegate method for dealing with failure to load stores.
[ADDED]     Now the delegate must be set at init time to reliably receive the store load notification that's needed to init your MOC.
[IMPROVED]  The PSC is now locked whenever it is unavailable (store loading) to prevent the application from using it.
[IMPROVED]  Much more robust store loading code.
[IMPROVED]  Better logging and more information in delegate methods.
[ADDED]     Missing nukeCloudContainer which deletes the entire application container from iCloud.
[UPDATED]   Example now uses new PSC API.
[ADDED]     Example now indicates loading progress.
[UPDATED]   Example now handles unavailable MOC.
[UPDATED]   Docs for delegate methods with usage recommendations.
[ADDED]     Also log detailed errors.
[FIXED]     Create the cloud content directory if it doesn't exist yet.
[FIXED]     Same destination MOC after copy migration.
[ADDED]     Support deletion of the cloud data on the device only (allowing it to be rebuilt from the iCloud data).
[IMPROVED]  More verbose error printing.
[IMPROVED]  Send willLoadStoreIsCloud to application when clearing the store so it knows the store is unavailable while it's being deleted too (in fact, whenever the PSC is cleared).
…t error.

[UPDATED]   Use clearStore to clear the PSC on error to make absolutely sure it's cleared.
[FIXED]     When a log import fails, reload the store to see if it's still viable to prevent the illusion that iCloud is still enabled and working while in reality it's broken.
[ADDED]     Yield the context of errors in failedLoadingStoreWithCause:.
[UPDATED]   Documentation for error causes specify what the context will be.
[ADDED]     Desync avoidance: An iOS bug causes the cloud store to break irreparably when validation relationships are modified on two devices simultaneously.
            Desync avoidance avoids the issue from occurring by ensuring only one device can modify the cloud store at a time.
            The developer has a choice between different strategies that determine what to do when the device cannot obtain exclusive access (ie. another device has exclusive access).
[MOVED]     The current identity is now stored as state in the manager and not persisted in the user defaults.  There is no need to persist it any longer than the store is open for.
…ent overwriting another device's ticket changes.

[FIXED]     Overwriting of other device's ticket changes in KVS.
[FIXED]     Don't remove observation of KVS & application events when clearing the store.
[UPDATED]   When cloud store is unavailable, don't fall back to the local store; wait for it to become available.
[REMOVED]   Desync avoidance strategies were unreliable and only worked while all devices are online.
[IMPROVED]  More robust handling of PSC locking and operation queues to avoid locking up under certain peculiar conditions (eg. deleting the container from another device or from the local device).
[IMPROVED]  Delete the stale store file when the store content is deleted to prevent corrupt cloud content from being created.
[IMPROVED]  Perform store deletion asynchronously.
[IMPROVED]  Notify the application immediately whenever the cloud store becomes unavailable so it can unset its MOCs and re-initialize its other persistence users (eg. fetchedResultsController).
[UPDATED]   A few more details about default implementations.
[ADDED]     A method of detecting cloud content corruption.
[ADDED]     When the cloud content is corrupted, all devices unload the cloud store and inform the delegate.
            The cloud store will no longer be available until the corruption is cleared.
            The documentation specifies approaches the application can take to clear the corruption (WIP).
[ADDED]     A method for migrating the cloud store to the local store.
[ADDED]     A method for rebuilding cloud content from the cloud store.
[FIXED]     Build fixes for cloud corruption handling code.
[FIXED]     Only reload the store on lack of corruption when it's detected as a cloud KVS change to avoid infinite-reloading of a non-corrupt cloud store.
[ADDED]     Recommended application handling code to the example.
[UPDATED]   Unified migration code and refactoring of store loading.
[FIXED]     Cloud -> local should happen with migration too, not just copying.
[FIXED]     When migrating by copying data, don't copy ubiquity metadata: Local stores may not have it and target cloud stores have their own.
[FIXED]     Add cloud options when opening a cloud migration store.
[FIXED]     Synchronize KVS before accessing its keys to get more up-to-date values.
[IMPROVED]  Slightly improved logging output.
[IMPROVED]  Don't override behaviour by implementing -ubiquityStoreManager:failedLoadingStoreWithCause:context:wasCloud:
[IMPROVED]  Synchronize all persistence methods by moving them onto the persistence queue.
[IMPROVED]  Post UbiquityManagedStoreDidChangeNotification after removing the persistence store from the coordinator.
[FIXED]     Issue where another device might recreate a cloud store before we get to after deleting the store.
[FIXED]     Tentative StoreUUID overrides KVS now to fix the above by not unsetting StoreUUID when deleting the store.
[ADDED]     Attempt to recover the cloud store after failing to load it by downloading and reimporting it from the cloud content.
[ADDED]     When the cloud store can't be opened, mark it as corrupted to avoid permanently locking the user out of iCloud.
[FIXED]     NSErrors were in some cases not logged.
lhunath added 7 commits March 18, 2013 23:56
[UPDATED]   Example UI now shows a much more friendly alert on cloud desync that just waits for the problem to be automatically fixed and offers a manual override option.
[IMPROVED]  Content corruption is handled much better now:
                - We keep track of whether the store is corrupt or only the content.
                - We record store and content as corrupt when the store fails to load too.
                - The default behavior can now often automatically recover corruption
                  when the user opens the app on another device.
[FIXED]     Situation where a double-fix of the cloud content might erase it all.
[ADDED]     Rebuild might fail when the cloud store is not viable or gone, possibility of falling back to rebuilding from the local store.
[FIXED]     Watching for cloud content deletion: deadlocks and bad test.
[IMPROVED]  Documentation and a bunch of bugs and side-effects throughout.
[UPDATED]   The example now shows a spinner telling the user to open the app on another device or giving him an option to override and rebuild anyway.
[ADDED]     A comprehensive overview of the API in README.markdown
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant