Framework Overview - nothirst/TICoreDataSync GitHub Wiki

Primary classes and requirements of the TICoreDataSync framework

TICoreDataSync adds synchronization capabilities to Core Data applications by tracking changes made to synchronized managed objects. These changes are pushed out to other clients during the sync process, and conflicts are handled on a “rolling sync” basis.

Primary Classes

If you are using one of the built-in synchronization types, most of the work you’ll need to do to integrate TICoreDataSync will be in creating, registering, and responding to the Sync Managers.

Sync Managers

There are two types of sync managers:

  1. Application Sync Manager - Responsible for registering your application for a specific type of sync, fetching a list of available documents that have already been synchronized by other clients, and downloading those documents. There is typically only one instance of an application sync manager in your application - an instance of one of the sync-specific subclasses of TICDSApplicationSyncManager.

  2. Document Sync Manager - Responsible for everything related to a single document, including registering the document for sync, uploading and downloading a copy of the entire store file, and the actual synchronization process. You’ll need one for each synchronized document - one of the sync-specific subclasses of TICDSDocumentSyncManager.

If you’re working with a non-document-based application, just treat the data as a single document (see the Mac Tutorial for a specific example).

Most of the individual sync manager tasks are carried out internally by operations. You don’t need to worry about these operations unless you wish to create your own set of classes to implement syncing via another service or protocol.

Both sync managers make use of a large number of delegate callbacks to alert you of progress, ask for input, or allow you to customize behavior. The available callbacks (some are required) are described by the TICDSApplicationSyncManagerDelegate and TICDSDocumentSyncManagerDelegate protocols.

Managed Objects and Contexts

Synchronized Managed Object

In order to properly track changes to your managed objects your application will need to use the framework's TICDSSynchronizedManagedObject class. This class recognizes when changes have been made and creates the necessary sync change objects to describe them.

Use the TICDSSynchronizedManagedObject subclass of NSManagedObject for every entity you wish to synchronize. You can either specify this class directly in your .xcdatamodel file or modify your custom NSManagedObject subclasses to inherit from TICDSSynchronizedManagedObject.

You will also need to add a persistent string attribute called ticdsSyncID to every entity in your data model that you wish to synchronize. The framework uses this attribute to track each object uniquely across multiple clients and sync sessions.

Managed Object Context

Your application's main NSManagedObjectContext will need to be marked as synchronized and passed to the document sync manager during registration. Each time this managed object context saves its changes will be recorded by the document sync manager. Every change that you wish to synchronize will need to take place in a synchronized managed object context.

How Synchronization Works

Although the framework supports uploading and downloading a copy of the entire Core Data persistent store file, the primary synchronization behavior involves working with Sync Changes.

Sync Changes

When changes are made to managed objects and saved in a synchronized managed object context, TICDSSyncChange objects are created to describe each type of change:

  1. Insertion - Managed objects have been inserted into the context.
  2. Attributes - Persistent attributes have been modified.
  3. Relationships - Persistent relationships have been modified.
  4. Deletion - Managed objects have been removed from the context.

These sync changes are kept locally in a dedicated file, stored inside a helper directory for the application (you can customize the location through delegate callbacks).

A brief note about relationships: Sync change objects are only created for one side of the relationship: either the to-one side of a one-to-many relationship, or the alphabetically-lower-named side of a one-to-one or many-to-many relationship. In the case of identically-named relationships the framework will currently create sync changes for both sides. This shouldn’t be a problem but will mean that the relationships will be set twice for any client applying the changes. The framework should also cope if you use one-way relationships (no inverse).

The Synchronization Process

When it comes time to synchronize, the following takes place:

  1. Download - Any sync changes that have been posted by other clients are downloaded from the remote.
  2. Apply - The changes are applied locally in a child context of the application's main context.
  3. Fix Conflicts - If conflicts are found with the local sync changes, these are either fixed automatically, or by asking the user/application for input via delegate callbacks.
  4. Upload - Once all conflicts have been fixed, the local set of sync changes are uploaded to the remote.

Note that the framework never accesses files directly on the remote. Existing files are always downloaded first, new files are always created locally before being uploaded. This behavior makes it easy to use TICoreDataSync over different protocols and services. The framework includes generic operations that handle everything that happens locally. Sync-specific subclasses simply override the methods relating to moving files between local and remote.

Encryption

TICoreDataSync supports optional encryption. If enabled, each of the following files will be encrypted when stored on the remote:

  1. WholeStore - A copy of the entire document store file.
  2. SyncChanges - Each set of changes made to managed objects.
  3. deviceInfo.plist - Information about a registered client.
  4. documentInfo.plist - Information about a synchronized document.

The framework handles encryption and decryption automatically, and is currently application-wide. This means that you’ll need to specify whether or not to enable encryption when the application is first registered with the remote from any device. When additional devices register for the first time, each one will need to provide the password before it can access any of the synchronized documents.

All you need to do is implement two delegate methods: one to specify whether encryption should be enabled, and one to provide a password from the user the first time it is needed. Once specified, this password is stored in the keychain and accessed automatically by the framework.

Compression

TICoreDataSync supports optional compression of the WholeStore file via the SSZipArchive open source package. If enabled the WholeStore file will be compressed before being uploaded and decompressed after being downloaded by other clients.