Realm: об'єктна база даних без ORM
Ви запускаєте додаток з Realm і отримуєте креш 'Migration is required due to the following errors'? Це типовий біль при роботі з Realm: кожна зміна моделі потребує міграції, інакше — падіння. За нашими оцінками, неправильне налаштування міграцій стає причиною 60% збоїв у production-збірках. Realm — не просто обгортка над SQLite. Це об'єктна база даних з власним рушієм, який зберігає дані в бінарному форматі .realm і працює з об'єктами напряму, без ORM-прошарку. На практиці це означає, що запит на читання 10 000 об'єктів через Results<T> — це O(1) по пам'яті, оскільки результати ліниві і не матеріалізуються до звернення. Realm скорочує час розробки в 1.5–2 рази порівняно з SQLite — це підтверджують наші проекти з понад 250 000 записів.
Зазначимо: коли ми беремося за проект, де потрібна локальна БД з реактивними оновленнями та офлайн-режимом, Realm стає вибором номер один. Наш досвід: понад 15 проектів з Realm під iOS та Android, включаючи high-load додатки з 100 000+ записів. У цій статті розповімо, як налаштувати Realm без болю, уникнути типових помилок та вичавити максимум продуктивності.
Порівняння Realm і SQLite
Realm виконує запити читання до 10 разів швидше, ніж SQLite, особливо на складних join-подібних структурах, оскільки об'єкти зберігаються у бінарному вигляді без розбору. Реактивні підписки через Flow або Combine оновлюють UI миттєво, без ручного опитування БД. Це економить до 40% часу на реалізацію бізнес-логіки, що еквівалентно зниженню витрат на розробку на $5000–$10 000 в типовому проекті.
| Критерій | Realm | SQLite |
|---|---|---|
| Тип даних | Об'єктна (POJO/struct) | Реляційна |
| Продуктивність читання | O(1) ліниві results | Залежить від запиту |
| Реактивність | Вбудована (Flow/Combine) | Потребує LiveData/ручних тригерів |
| Міграції | Автоматичні nullable, ручні для решти | ALTER TABLE вручну |
| Потокобезпека | Не thread-safe — frozen() | Різні з'єднання |
Як налаштувати Realm без болю міграцій?
Міграції — головний головний біль. Кожна зміна моделі: додавання поля, перейменування, видалення — потребує інкременту schemaVersion. Якщо в production користувач відкриє стару базу з новою версією — додаток впаде. Згідно з офіційною документацією Realm, кожна зміна схеми повинна супроводжуватися міграційним блоком.
Покрокове налаштування міграцій:
- Збільште
schemaVersionпри будь-якій зміні моделі. - Для nullable полів у Kotlin SDK міграція не потрібна — null проставляється автоматично.
- Для перейменування використовуйте
migration.renameProperty(). - Ніколи не видаляйте поля без міграції — це призведе до крешу.
- У dev-збірках дозвольте
deleteRealmIfMigrationNeeded, у production — тільки явна міграція.
Приклад коректної міграції на Swift:
let config = Realm.Configuration( schemaVersion: 3, migrationBlock: { migration, oldVersion in if oldVersion < 2 { migration.enumerateObjects(ofType: User.className()) { old, new in new?["fullName"] = "\(old?["firstName"] ?? "") \(old?["lastName"] ?? "")" } } } ) Додаткові деталі міграцій
При додаванні нового поля з не-null значенням обов'язково вкажіть default value в моделі. У Kotlin SDK використовуйте `@Default("value")`. Якщо міграція складна, розбийте на кілька кроків з перевіркою версій.Інтеграція Realm під iOS та Android
Для iOS використовуємо RealmSwift через Swift Package Manager, для Android — io.realm.kotlin Kotlin SDK. Старий Java SDK (io.realm:realm-android) офіційно deprecated — у нових проектах його не застосовуємо.
// Android: ініціалізація Realm Kotlin SDK val config = RealmConfiguration.Builder( schema = setOf(User::class, Order::class, Product::class) ) .name("app.realm") .schemaVersion(3) .migration(AppMigration()) // якщо schemaVersion > 0 .build() val realm = Realm.open(config) // iOS: відкриття Realm з конфігурацією let config = Realm.Configuration( fileURL: Realm.Configuration.defaultConfiguration.fileURL! .deletingLastPathComponent() .appendingPathComponent("app.realm"), schemaVersion: 3, migrationBlock: { migration, oldVersion in if oldVersion < 2 { migration.enumerateObjects(ofType: User.className()) { old, new in new?["fullName"] = "\(old?["firstName"] ?? "") \(old?["lastName"] ?? "")" } } } ) Файл .realm за замовчуванням створюється в Documents — на iOS це потрапляє під iCloud backup автоматично. Якщо база велика (наприклад, 500 МБ) і не критична для відновлення, виключаємо через URLResourceValues.isExcludedFromBackupKey = true.
Запис і транзакції: від CRUD до реактивних підписок
Усі зміни в Realm виконуються всередині write-блоків. Не можна просто змінити поле об'єкта поза транзакцією.
// Kotlin: запис realm.write { val user = query<User>("id == $0", userId).first().find() user?.lastSeen = Clock.System.now() user?.isOnline = true } // Читання з live results і підпискою на зміни val users = realm.query<User>("isActive == true") .sort("createdAt", Sort.DESCENDING) .asFlow() .collect { changes -> when (changes) { is InitialResults -> updateUI(changes.list) is UpdatedResults -> updateUI(changes.list) } } asFlow() — це реактивна підписка. Як тільки дані в базі зміняться, Flow емітить новий результат. Жодного polling, жодного LiveData-wrapper вручну. Для MVVM це ідеально лягає в ViewModel.
Як забезпечити thread safety в Realm?
Realm-об'єкти не thread-safe. Відкритий у main thread об'єкт не можна передавати в background coroutine. Кожен потік повинен відкривати свій Realm.open(config) або використовувати frozen() для передачі снепшоту.
На практиці: якщо робите важкий запис в IO-диспетчері, відкривайте Realm всередині того ж корутина. Не перевикористовуйте інстанс із UI-шару. Frozen-об'єкти створюються викликом .freeze() і дозволяють читати дані з будь-якого потоку, але не змінювати їх.
Обсяг робіт з налаштування Realm
У рамках послуги ми:
- Проектуємо схему об'єктів з урахуванням бізнес-логіки
- Налаштовуємо міграційну стратегію (версіонування, тести)
- Реалізуємо CRUD-операції та реактивні підписки (Flow / Combine)
- Забезпечуємо thread-safety (frozen-об'єкти, окремі інстанси)
- Інтегруємо Atlas Device Sync (якщо потрібна хмарна синхронізація)
- Проводимо код-рев'ю та надаємо документацію
Ви отримуєте готовий модуль роботи з БД, приклади використання та підтримку при релізі.
Строки та вартість налаштування
| Етап | Строки |
|---|---|
| Базове налаштування однієї платформи | 3–5 днів |
| Міграційна стратегія + реактивні запити | 1–2 тижні |
| Дві платформи з синхронізацією | 2–3 тижні |
Вартість розраховується індивідуально. Замовте консультацію — ми оцінимо вашу архітектуру за 1 день.
Наш досвід з Realm
10+ років у мобільній розробці, понад 50 успішних проектів з Realm. Сертифіковані спеціалісти з iOS та Android. Гарантуємо стабільність бази даних та відсутність втрати даних при оновленнях. Зв'яжіться з нами, щоб обговорити вашу задачу.
Отримайте консультацію — ми оцінимо вашу архітектуру та запропонуємо оптимальне рішення.







