Ответ
Преимущества:
- Высокая производительность: Использует собственный движок хранения, оптимизированный для объектов. Часто работает быстрее, чем Core Data с SQLite в качестве бэкенда, особенно на операциях чтения и фильтрации.
- Реактивные обновления: Подписки (
observe) иResultsавтоматически обновляются при изменении данных, что идеально подходит для связки с UI (например, с UITableView). - Прямой доступ к объектам: Не требуется контекст или фетч-запросы для получения объектов. Модели наследуются от
Objectи сразу готовы к работе. - Простая миграция для схемы: Для добавления/удаления полей часто достаточно просто изменить класс модели. Удаление полей и сложные преобразования требуют ручной логики в блоке миграции.
- Кроссплатформенность: Одна и та же база данных (файл
.realm) может использоваться на iOS, Android и других платформах.
Недостатки и ограничения:
- Размер файла базы данных: Может быстро расти, так Realm резервирует пространство. Требуется периодическое сжатие (
Realm.Configuration.shouldCompactOnLaunchилиwriteCopy). - Модель данных наследует от
Object: Это накладывает ограничения на дизайн моделей (например, нельзя наследовать от других пользовательских классов). - Потоковая безопасность: Объекты Realm привязаны к потоку, на котором были созданы. Для передачи между потоками необходимо использовать
ThreadSafeReferenceили заново запрашивать объект по первичному ключу в другом потоке. - Отсутствие каскадного удаления "из коробки": При удалении родительского объекта связанные дочерние объекты не удаляются автоматически, это нужно делать вручную.
- Проприетарная лицензия: Для некоторых сценариев использования требуется коммерческая лицензия.
Примеры использования и миграции:
// 1. Определение модели
import RealmSwift
class Dog: Object {
@Persisted(primaryKey: true) var id: ObjectId
@Persisted var name: String
@Persisted var age: Int
@Persisted var owner: Person? // To-one связь
@Persisted var toys: List<Toy> // To-many связь
}
// 2. Конфигурация с шифрованием и миграцией
let config = Realm.Configuration(
schemaVersion: 2,
encryptionKey: getEncryptionKey(),
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion < 2 {
// Миграция с версии 1 на 2: добавляем новое поле 'breed'
migration.enumerateObjects(ofType: Dog.className()) { oldObject, newObject in
newObject!["breed"] = "Unknown"
}
}
}
)
let realm = try! Realm(configuration: config)
// 3. Реактивные наблюдения
let puppies = realm.objects(Dog.self).filter("age < 2")
let token = puppies.observe { changes in
switch changes {
case .initial(let results):
print("Initial load: (results.count) puppies")
case .update(let results, let deletions, let insertions, let modifications):
// Автоматически обновить UITableView/UICollectionView
print("Changes: +\(insertions.count), -\(deletions.count), ~\(modifications.count)")
case .error(let error):
print("Error: (error)")
}
}
// 4. Запись в транзакции
try! realm.write {
let newDog = Dog()
newDog.name = "Rex"
newDog.age = 1
realm.add(newDog)
}
// Не забудьте инвалидировать токен наблюдения
// token.invalidate()