Skip to content

Strategy for MotionModel Persistence

s.ross edited this page Dec 30, 2013 · 1 revision

This document refers only to the ArrayModelAdapter branch of MotionModel.

Abstract

MotionModel is designed to feel like pretty much any ActiveRecord, DataMapper, ActiveModel ORM in the Ruby space. As such, it utilizes a good deal of muscle memory that Rails programmers, in particular, have developed. Beneath the covers, though, the AMA (ArrayModelAdapter) interacts with the backing store far differently than an ORM that wraps a database engine.

To be clear, the whole idea behind MotionModel was to provide a light wrapper around NSCoding but the wrapper evolved I implementation to feel much more like it was talking to a database. That is not what is happening.

Think of your iOS device as having two different "sorts" of memory: volatile (aka RAM or application memory) and non-volatile memory where data is persistent. When you do a save in MotionModel, it's reasonable to expect that you have affected the persistent data store. That's not what happens, however. All of your CRUD operations are cached in volatile memory until you specifically serialize it using one of the serialization APIs.

You might wonder why this implementation decision was made; simple: it's better to have more choice than less when operations that involve some expense are concerned. Serialization, in this context, means the copying of all objects from volatile memory to the backing store. In the small, this doesn't seem like much of a deal. Say a user makes an entry involving 5 fields. It's unlikely they would notice any performance hit if you did both a save and persist. Especially if the data set is small.

However, if your application fetches data remotely, all this copying can become a performance issue. So that drove the decision to separate CRUD operations from persistence, allowing the user discretion with respect to how often data is persisted.

Proposal

Thus far, the issue has only come up once, but this can be repaired programmatically. Here's a sketch of what it would take:

class MyClass
  include MotionModel::Model
  include MotionModel::ArrayModelAdapter
  include MotionModel::AutoPersist
  
  persists_to 'your/file/path'
  persistence_strategy :synchronous_copy # Persist every save, etc.
  columns :whatever
end

The new wrinkles here are the new module MotionModel::AutoPersist And some macros it would introduce:

persists_to specifies a file name for the backing store. If not specified, a lowercase pluralized version of the model name is used.

persistence_strategy allows you to choose whether to persist via:

  • :synchronous_copy, options -- Copy and block
  • :asynchronous_copy, options -- Copy off main thread

Options are:

  • :change_limit: <threshold> Persists every so often

Finally, you can call persist! at any point should you need to make certain your data is serialized.

To solve the problem of remote hydration, the following APIs are provided:

  • auto_persist_off temporarily suspends automatic persistence behavior.
  • auto_persist_on restores automatic persistence state to that declared in the model.

Alternatively, you can call:

without_serialization do
  # Hydrate the collection
end

This suspends automatic persistence for the duration of the block, restoring it on exit.

Clone this wiki locally