RestKit/RestKit — pull request #573 by ecordell (2012-02-26 23:54:26+00:00)
Title: RKSyncManager - monitors Core Data changes and syncs with server

It's taken me a long time to get back to RestKit, and I apologize for the delay. You might remember an old [pull request](https://github.com/RestKit/RestKit/pull/197) with a clunkier implementation of this idea. This pull request is a ground-up redesign of the old idea, and includes many of the suggestions from the discussion on the aforelinked pull request.

Basic idea:
An RKSyncManager object is created automatically when an RKObjectStore is initialized. It holds onto a reference to the associated RKManagedObjectManager, and that sync manager only manages syncronization of objects registered with that objectManager and that exist in that objectStore. I.e. multiple objectManagers will have multiple syncManagers, and you can even register multiple syncManagers (for whatever reason) for the same objectManager.

RKManagedObjectMapping is modified to have a syncMode property. This can be set to RKSyncModeNone (the default), RKSyncModeTransparent, RKSyncModeInterval, or RKSyncModeManual.

* RKSyncModeNone - the sync manager will not track changes to objects with this syncMode.
* RKSyncModeTransparent - the sync manager will pass all changes directly to the server if a connection is available; otherwise it archives the changes and pushes them whenever a connection becomes available.
* RKSyncModeManual - the sync manager will only sync these objects when a call is made to one of the sync methods (on the RKSyncManager object)
* RKSyncModeInterval - this is sort of a dummy mode for objects that will be synced on a timed interval. Its only purpose is to prevent objects with this type from being synced manually or transparently.

The design is such that the most common use cases are very, very easy to implement, but there is still lots of flexibility and control over when and how syncing happens.

For example, to "transparently" sync objects with a server, simply set `syncMode = RKSyncModeTransparent` on the object mapping, and define the routes for the object on the router. That's all - the data on the server will now always reflect what's on the iPhone and vice-versa.

Or if you'd like to manually sync (say, when a user chooses to update), simply set the syncMode to RKSyncModeManual and define the routes for the mapping, and then call `[objectManager.syncManager sync]'

Or if you'd like to sync objects every 60s, simply create an NSTimer that calls `[objectManager.syncManager syncObjectsWithSyncMode:RKSyncModeInterval andClass:nil]`

And you can set different syncModes for different mappings, and have three different objects: one which syncs transparently, one which syncs manually, or one that syncs on an interval.

Or if that's not enough, you have super-fine control over what gets synced with the following methods:

```
- (void)syncObjectsWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

- (void)pushObjectsWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

- (void)pullObjectsWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;
```

In addition to a rich set of delegate callbacks defined in RKSyncManagerDelegate:

```
- (void)syncManager:(RKSyncManager *)syncManager didFailSyncingWithError:(NSError*)error;

- (void)syncManager:(RKSyncManager *)syncManager willSyncWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

- (void)syncManager:(RKSyncManager *)syncManager didSyncWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

- (void)syncManager:(RKSyncManager *)syncManager willPushObjectsInQueue:(NSArray *)queue withSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

- (void)syncManager:(RKSyncManager *)syncManager willPullWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

- (void)syncManager:(RKSyncManager *)syncManager didPushObjectsWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

- (void)syncManager:(RKSyncManager *)syncManager didPullWithSyncMode:(RKSyncMode)syncMode andClass:(Class)objectClass;

```

This is all up for review right now. I have written documentation (as you can see in the pull request) but it might be incomplete or unclear, and appledocs doesn't want to work for me right now, so I can't read it easily.

I haven't yet written tests it, because I'm still unsure of the best way to do so. I'm not sure that a thin Sinatra app will suffice, it may require a full rails app. That said, you can grab the simple app I've been using to test it [here](https://github.com/ecordell/RestKitDev).