FTASync
Allows you to sync CoreData entities with a Parse backend. FTASync supports relationships (many-to-many have not been tested), conflict resolution (last in wins), custom data class names, and multiple levels of inheritance. For conflict resolution each relationship is in it's own conflict domain, but all entity attributes are currently in a single conflict domain.
As with any open source code, do your own due diligence before putting this in a production app! There are a few known issues that still need addressed. They are listed below.
Because sync and conflict resolution is very complex, there is bunch of debug logging in place. If you don't want to see all of that, you can turn it off in FTASync.h.
Requires
It is assumed that you have already installed and setup these:
- Magical Record - Easier handling of the CoreData stuff. (Note: FTASync uses MR 2.0 and will not work with earlier versions)
- [mogenerator] (https://github.com/rentzsch/mogenerator) - If you've never used it you should.
- [NPReachability] (https://github.com/Abizern/NPReachability) - Used to check for network connectivity pre-sync.
- Parse SDK
- (Optional) Crashlytics
Installation
- Add a new data model version.
- Add a new abstract entity to the data model and name it (and it's class name) FTASyncParent. Add the following attributes:
- BOOL createdHere (Default: YES)
- BOOL deleted (Default: NO)
- String objectId
- Int16 syncStatus (Default: 2)
- Date updatedAt
- For each entity that should sync, set the parent entity field to FTASyncParent.
- Run mogenerator to generate your entity class files.
- Add all the .h and .m files from the Source folder into your project. (FTASyncParent.h/m will replace the mogenerator generated files)
- Add FTASync.h to your AppDelegate file.
- Create a file with the name ParseKeys.h with these two lines:
#define kParseAppId @"<Your Parse App ID>"
#define kParseClientKey @"<Your Parse Client Key>"
- (Optional)
#define kCrashlyticsKey @"<Your Crashlytics Key>"
- Add
[FTASyncHandler sharedInstance];
to the- (BOOL)application:didFinishLaunchingWithOptions:
method in your AppDelegate. - Add
[PFACL setDefaultACL:[PFACL ACL] withAccessForCurrentUser:YES];
to the- (BOOL)application:didFinishLaunchingWithOptions:
method in your AppDelegate. You can also setup some other ACL if you wish. - (Optional) Uncomment out
//[Crashlytics startWithAPIKey:kCrashlyticsKey];
in the- (BOOL)application:didFinishLaunchingWithOptions:
method in your AppDelegate.
It is assumed that you will handle user sign up and login on your own.
Usage
Sync all entities
Simply add FTASync.h and call [[FTASyncHandler sharedInstance] syncWithCompletionBlock:nil progressBlock:nil];
.
Optionally you can pass in completion and progress blocks. The signatures are in FTASyncHandler.h
Sync a specific entity
Not supported yet.
Display the "Last Sync" time
There is an FTASyncLastSyncDate
key added to the user defaults that contains the time of the last successful sync. Each time that value is updated an FTASyncDidSync
notification is posted to the default notification center.
Reset sync
To reset all local objects to "new" objects call [[FTASyncHandler sharedInstance] resetAllSyncStatusAndDeleteRemote:YES withCompletionBlock:nil progressBlock:nil];
Optionally you can pass in completion and progress blocks. The signatures are in FTASyncHandler.h
If you want to completely reset a user's Parse account, then pass YES
for the first parameter and all remote objects will be deleted. Calling a sync after doing this will complete a full sync reset on the remote, forcing it to match the local data. Or, you can then delete all local data for a complete data reset.
NOTE: If you call this and pass NO
as the first parameter, and then sync to the same Parse account, you will get duplicate objects!
Known Issues/Limitations
- Queries are limited to a return of 1000 objects by Parse
ToDo
- Support sync of a single entity
- Add ability to check PFUser for updates on any other entity to save on API calls
- PFQuery is limited to 1000 returned objects, so support pagination beyond that
- Write unit tests
Pull Requests
I appreciate any pull requests, and will try my best to keep them merged into the main project. However, it makes my life much easier if they are tested! Testing sync code is not easy, especially with relationships and conflict resolution. To make things a little easier for you, I have included my test process (see TestProcess.mdown and TestDiagram.png). There is also a lot of logging in the code to make tracking down bugs easier. As mentioned above, this can be turned off in FTASync.h.
Apps Using FTASync
Our List by Five3 Apps
If you use FTASync in an app I'd love to hear about it, and add it to this list if you wish.
License
I am making this source code available for free under the MIT license. For the full license details see LICENSE.txt
Also, I am making the source code for a sample ToDo app (FTASyncDemo) available for free under the MIT license. This license grants you the right to do anything you like with the source code. However, you are asked not to re-submit the app as-is to Apple for App Store review. I have worked to create this sample app so you can learn how to utilize FTASync in your own app. So please, don't be a dick and re-submit it as your own to Apple. However, feel free to pull bits and pieces out and use them however you wish :).
Acknowledgements
Thanks to all the folks at the Colorado Springs, CO NSCoderNight for the code reviews and ideas. Special thanks to Tom Harrington for his debugging and architectural help!
Big thanks also to Duane Fields for providing code that I used to handle the overall sync management and threading!