Designing Mobile Persistence Architecture with Virtual Record and DataCenter
This article explains how to choose and design persistence solutions for iOS apps, covering NSUserDefaults, Keychain, file storage, databases, isolation between persistence and business layers, multithreading, and the Virtual Record pattern implemented via DataCenter and CTPersistance.
Preface
Persistence solutions, whether on the server or client, are a hot topic because they can significantly affect performance; on mobile, maintainability and extensibility are usually more important than raw speed. This article focuses on the design of a mobile persistence layer, embedding performance tuning within each section.
The persistence layer often becomes the main source of coupling in an app architecture, so I continue the practice of de‑modeling by introducing a Virtual Record design, which is described in detail later.
Choosing a Persistence Scheme Based on Requirements
When persistence is needed, many options exist: NSUserDefaults, Keychain, file storage, and various database‑based solutions.
NSUserDefaults
Suitable for small, weakly related data. Storing large or strongly related data in NSUserDefaults is a bad practice (example: the Taobao app mixes everything into NSUserDefaults, which is a maintenance nightmare).
Keychain
Provides reversible encryption, survives app uninstall, and can be synced via iCloud. Ideal for sensitive small data such as user identifiers.
File Storage
Includes Plist, archive, and stream methods. Structured data is often persisted as Plist; large or rarely used data can be archived; streams are used for images and other frequently accessed but not huge files.
Database Storage
iOS offers Core Data and many third‑party alternatives (FMDB, etc.). When data has a clear state and category that are strongly business‑related, a database is the preferred solution. Large binary assets (images, articles) are usually stored as file names in the database, with the actual files kept on disk.
In short, use NSUserDefaults, Keychain, or simple file storage for trivial data; for anything that requires strong business semantics, adopt a database‑based approach.
Isolation Considerations When Implementing the Persistence Layer
The following aspects of isolation should be addressed:
Isolation between persistence and business layers
Database read/write isolation
Multithreading‑induced isolation
Isolation of storage methods and schemes
Isolation of data expression and data operations
1. Persistence‑Business Layer Isolation
About Model
Earlier I introduced the concepts of fat Model and skinny Model , and advocated a de‑modeling approach in the network layer. The same ideas apply to the persistence layer: the persistence side can use a fat Model while the network side uses de‑modeling , and they complement each other.
Confusion often arises when architects mix the terms Model and Model Layer . Clarifying the distinction helps avoid architectural decay.
Data Model
A Data Model describes how business data is represented in code (byte streams, JSON, objects, etc.). The choice of representation follows the business requirements.
Model Layer
The Model Layer is responsible for CRUD operations. A skinny Model typically stops at CRUD, while a fat Model also provides caching, synchronization, and weak‑business handling.
My Preference
I prefer de‑modeling in the network layer (implemented by a reformer ) and Virtual Record in the persistence layer. Reducing the influence of concrete models weakens coupling and makes migration easier.
Database Read/Write Isolation
On the web, read/write splitting improves response speed; on iOS, it improves code maintainability. The goal is not to separate read and write operations per se, but to define a boundary beyond which data objects are immutable for the business layer.
Core Data does not enforce such isolation; any change to an NSManagedObject is persisted on save . In my experience, Core Data is over‑engineered for many mobile use‑cases, leading to hacks and higher learning curves.
SQLite supports three threading modes: Single Thread (not thread‑safe), Multi Thread (connections cannot be shared), and Serialized (default, uses a serial queue). For most mobile apps, Serialized mode offers a good balance of safety and performance.
Multithreading‑Induced Isolation
Core Data
In multithreaded scenarios, Core Data requires a private‑queue context with its parentContext on the main thread. Objects should be passed by NSManagedObjectID , not by direct pointer.
SQLite
SQLite’s Multi Thread mode locks the whole database with a read/write lock; Serialized mode uses a single queue, which is usually sufficient for mobile apps.
Isolation of Data Expression and Data Operations
Active Record mixes data expression with data operations, leading to tight coupling. Separating Table (weak business) from Record (strong business) improves extensibility and migration.
Interaction Between Persistence and Business Layers
The diagram below illustrates how DataCenter (business‑friendly API) interacts with Virtual Record and CTPersistance tables.
-------------------------------------------
| |
| LogicA LogicB LogicC | -------------------------------> View Layer
| \ / | |
-------\-------/------------------|--------
\ / |
\ / Virtual | Virtual
\ / Record | Record
| |
-----------|----------------------|--------
| | | |
Strong Logics | DataCenterA DataCenterB |
| / \ | |
-----------------|-------/-----\-------------------|-------| Data Logic Layer ---
| / \ | | |
Weak Logics | Table1 Table2 Table | |
| \ / | | |
--------\-----/-------------------|-------- |
\ / | |--> Data Persistance Layer
\ / Query Command | Query Command |
| | |
-----------|----------------------|-------- |
| | | | |
| | | | |
| DatabaseA DatabaseB | Data Operation Layer ---
| |
| Database Pool |
-------------------------------------------DataCenter provides business‑friendly interfaces (strong logic) and delegates weak logic to CTPersistanceTable . Each Table generates SQL via a QueryCommand and talks to the underlying database.
Interaction Scenarios
One‑to‑One Interaction
Typical case where a business object fetches a Virtual Record and directly displays it. The code is straightforward and omitted here.
Many‑to‑One Interaction
Multiple view objects contribute parts of a record (e.g., nickname, avatar, token) that together form a complete Virtual Record . The mergeRecord:shouldOverride: method combines them.
/* RecordViewA, RecordViewB, RecordViewC implement mergeRecord:shouldOverride: */
RecordViewA *a;
RecordViewB *b;
RecordViewC *c;
/* Collect values … */
[[a mergeRecord:b shouldOverride:YES] mergeRecord:c shouldOverride:YES];
[self.dataCenter saveRecord:a];One‑to‑Many Interaction
One object may need data from several tables (vertical slicing) or display data from different tables (horizontal slicing). The same mergeRecord approach is used for both storing and retrieving.
/* Store */
[self.CasaTable insertRecord:a error:NULL];
[self.TaloyumTable insertRecord:a error:NULL];
[self.CasatwyTable insertRecord:a error:NULL];Many‑to‑Many Interaction
Combines the previous patterns; implementation is identical, so it is omitted.
Summary of Interaction Schemes
Separate strong and weak business by distinguishing Data Model into Table (weak) and Record (strong). DataCenter implements strong logic, while Table implements weak logic. Benefits include reduced coupling, easier migration, read/write isolation, and a solid foundation for the Virtual Record pattern.
Using Virtual Record moves data adaptation logic into concrete record implementations, resulting in cleaner, more maintainable code.
Finally, a brief note on database slicing (vertical and horizontal) as performance‑optimisation techniques for mobile apps.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.