配置并打开 Realm - Swift SDK
在此页面上
打开域时,可以传递 Realm ,用于指定有关如何配置域文件的其他详细信息。 这包括:
传递 FileURL 或内存标识符以自定义该 Realm 在设备上的存储方式
提供已登录用户和 Sync 详细信息,以将 Sync 与 Realm 一起使用
指定 Realm 仅使用应用的部分类
是否以及何时压缩 Realm 以减小其文件大小
传递加密密钥以加密 Realm
执行模式更改时提供模式版本或迁移区块
在没有同步的情况下开启 Realm
您可以使用以下几种不同的配置选项来打开未同步的本地 Realm:
无配置 - 即默认认配置
指定 Realm 的文件 URL
仅在内存中打开 Realm,而不将文件保存到文件系统
复制已同步的 Realm 以便在不使用同步的情况下使用
打开默认 Realm 或通过文件 URL 打开 Realm
您可以使用+[RLMRealm defaultRealm]打开默认域 。
您还可以将RLMRealmConfiguration对象传递给+[RLMRrealm realmWithConfiguration:error:] ,以在特定文件URL、内存中或使用Device Sync打开域 。
您可以通过将 RLMRealmConfiguration实例传递给+[RLMRealmConfiguration setDefaultConfiguration:]来设立默认域配置。
// Open the default realm RLMRealm *defaultRealm = [RLMRealm defaultRealm]; // Open the realm with a specific file URL, for example a username NSString *username = @"GordonCole"; RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration]; configuration.fileURL = [[[configuration.fileURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:username] URLByAppendingPathExtension:@"realm"]; NSError *error = nil; RLMRealm *realm = [RLMRealm realmWithConfiguration:configuration error:&error];
您可以使用 Realm() 初始化方法打开一个域。如果省略 Realm.Configuration 参数,则将打开默认域。
可以为 Realm.Configuration.defaultConfiguration 类属性分配一个新的 Realm.Configuration 实例,以设置默认的域配置。
// Open the default realm let defaultRealm = try! Realm() // Open the realm with a specific file URL, for example a username let username = "GordonCole" var config = Realm.Configuration.defaultConfiguration config.fileURL!.deleteLastPathComponent() config.fileURL!.appendPathComponent(username) config.fileURL!.appendPathExtension("realm") let realm = try! Realm(configuration: config)
打开内存中 Realm
已在 10.46.0 版本中更改:支持在内存中打开同步的数据库。
您可以完全在内存中打开一个 Realm,这样就不会创建 .realm
文件或其关联的辅助文件。相反,SDK 会在 Realm 处于打开状态时将对象存储在内存中,并在所有实例关闭后立即丢弃它们。
请注意,该属性不能与 fileURL
结合使用。在 Swift SDK 版本 10.45.3 和更早版本中,该属性不能与 syncConfiguration
结合使用。
设置 Realm 配置的 inMemoryIdentifier 属性。
// Open the realm with a specific in-memory identifier. NSString *identifier = @"MyRealm"; RLMRealmConfiguration *configuration = [[RLMRealmConfiguration alloc] init]; configuration.inMemoryIdentifier = identifier; // Open the realm RLMRealm *realm = [RLMRealm realmWithConfiguration:configuration error:nil];
设置 Realm 配置的 inMemoryIdentifier 属性。
// Open the realm with a specific in-memory identifier. let identifier = "MyRealm" let config = Realm.Configuration( inMemoryIdentifier: identifier) // Open the realm let realm = try! Realm(configuration: config)
重要
当所有具有给定标识符的内存中 Realm 实例都超出作用域时,Realm 会删除该 Realm 中的所有数据。为了避免这种情况,请在应用程序的生命周期中保持对任何内存中 Realm 的强引用。
使用 Swift 并发功能打开 Realm
您可以使用 Swift 的异步/等待语法打开 Mainactor 隔离的 Realm,或者在异步打开 Realm 时指定一个 actor:
func mainThreadFunction() async throws { // These are identical: the async init produces a // MainActor-isolated Realm if no actor is supplied let realm1 = try await Realm() let realm2 = try await Realm(actor: MainActor.shared) try await useTheRealm(realm: realm1) }
或者,您可以定义一个自定义 Realm actor 来管理所有 Realm 操作:
actor RealmActor { // An implicitly-unwrapped optional is used here to let us pass `self` to // `Realm(actor:)` within `init` var realm: Realm! init() async throws { realm = try await Realm(actor: self) } var count: Int { realm.objects(Todo.self).count } func createTodo(name: String, owner: String, status: String) async throws { try await realm.asyncWrite { realm.create(Todo.self, value: [ "_id": ObjectId.generate(), "name": name, "owner": owner, "status": status ]) } } func getTodoOwner(forTodoNamed name: String) -> String { let todo = realm.objects(Todo.self).where { $0.name == name }.first! return todo.owner } struct TodoStruct { var id: ObjectId var name, owner, status: String } func getTodoAsStruct(forTodoNamed name: String) -> TodoStruct { let todo = realm.objects(Todo.self).where { $0.name == name }.first! return TodoStruct(id: todo._id, name: todo.name, owner: todo.owner, status: todo.status) } func updateTodo(_id: ObjectId, name: String, owner: String, status: String) async throws { try await realm.asyncWrite { realm.create(Todo.self, value: [ "_id": _id, "name": name, "owner": owner, "status": status ], update: .modified) } } func deleteTodo(id: ObjectId) async throws { try await realm.asyncWrite { let todoToDelete = realm.object(ofType: Todo.self, forPrimaryKey: id) realm.delete(todoToDelete!) } } func close() { realm = nil } }
角色隔离式 Realm 可同时与本地角色或全局角色一起使用。
// A simple example of a custom global actor actor BackgroundActor: GlobalActor { static var shared = BackgroundActor() } func backgroundThreadFunction() async throws { // Explicitly specifying the actor is required for anything that is not MainActor let realm = try await Realm(actor: BackgroundActor.shared) try await realm.asyncWrite { _ = realm.create(Todo.self, value: [ "name": "Pledge fealty and service to Gondor", "owner": "Pippin", "status": "In Progress" ]) } // Thread-confined Realms would sometimes throw an exception here, as we // may end up on a different thread after an `await` let todoCount = realm.objects(Todo.self).count print("The number of Realm objects is: \(todoCount)") } func mainThreadFunction() async throws { try await backgroundThreadFunction() }
有关使用 actor 隔离的 Realm 的更多信息,请参阅结合使用 Realm 与 Actor - Swift SDK。
关闭 Realm
在 Swift 或Objective-C中,无需手动关闭域 。当域超出范围并由于 ARC 从内存中删除时 ,该域已关闭。
处理访问 Realm 时出现的错误
要处理访问 Realm 时的错误,请提供指向error
参数的NSError
指针:
NSError *error = nil; RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error]; if (!realm) { // Handle error return; } // Use realm
要处理访问 Realm 时的错误,请使用 Swift 的内置错误处理机制:
do { let realm = try Realm() // Use realm } catch let error as NSError { // Handle error }
向 Realm 提供类的子集
提示
在低内存限制下运行
某些应用程序(例如 watchOS 应用和 iOS 应用扩展)对其内存占用有严格的限制。要针对低内存环境优化数据模型,请使用类的子集打开 Realm。
默认情况下,Swift SDK 会自动将可执行文件中的所有RLMObject和RLMEmbeddedObject派生类添加到 Realm 模式中。 您可以通过设置 RLMRealmConfiguration 对象的 objectClasses 属性来控制添加哪些对象。
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; // Given a RLMObject subclass called `Task` // Limit the realm to only the Task object. All other // Object- and EmbeddedObject-derived classes are not added. config.objectClasses = @[[Task class]]; NSError *error = nil; RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error]; if (error != nil) { // Something went wrong } else { // Use realm }
默认, Swift SDK会自动将可执行文件中所有Object和EmbeddedObject派生类添加到域模式中。 您可以通过设置 Realm 对象的 objectTypes 属性来控制添加哪些对象。
var config = Realm.Configuration.defaultConfiguration // Given: `class Dog: Object` // Limit the realm to only the Dog object. All other // Object- and EmbeddedObject-derived classes are not added. config.objectTypes = [Dog.self] let realm = try! Realm(configuration: config)
使用 Realm API 初始化属性
您可以定义这样一个属性,其值使用 Realm API 进行初始化。例如:
class SomeSwiftType { let persons = try! Realm().objects(Person.self) // ... }
如果这个初始化代码在您设置 Realm 配置之前运行,可能会出现意外行为。例如,如果您在 applicationDidFinishLaunching()
中为默认 Realm 配置设置了迁移块,但在 applicationDidFinishLaunching()
之前创建了 SomeSwiftType
的实例,那么您可能会在正确配置 Realm 之前访问 Realm。
为了避免此类问题,请考虑执行以下操作之一:
将任何过早使用 Realm API 初始化属性的类型实例化推迟到您的应用完成其 Realm 配置的设置之后。
使用 Swift 的
lazy
关键字定义您的属性。这样一来,您就可以在应用程序生命周期中随时安全地实例化此类类型,但前提是您在应用设置其 Realm 配置之前不要尝试访问您的lazy
属性。仅使用显式接受用户定义配置的 Realm API 来初始化您的属性。您可以确定所使用的配置值在用于打开 Realm 之前已正确设置。
在设备锁定时使用 Realm
默认情况下,每当设备锁定时,iOS 8 及更高版本都会使用 NSFileProtection
加密应用文件。如果您的应用在设备锁定时尝试访问 Realm,您可能会看到以下错误:
open() failed: Operation not permitted
为此,请降低包含处理Realm的文件夹的文件保护级别。 不太严格的保护级别,例如 NSFileProtectionCompleteUntilFirstUserAuthentication 即使设备锁定时也允许访问权限文件。
提示
如果您降低了 iOS 文件的加密级别,请考虑使用 Realm 的内置加密来保护您的数据。
此示例展示了如何对默认 Realm 的父目录应用不太严格的保护级别。
let realm = try! Realm() // Get the realm file's parent directory let folderPath = realm.configuration.fileURL!.deletingLastPathComponent().path // Disable file protection for this directory after the user has unlocked the device once try! FileManager.default.setAttributes([FileAttributeKey.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication], ofItemAtPath: folderPath)
Realm 可以随时创建和删除辅助文件。不必降低每个文件的保护级别,而是将此操作应用于父文件夹。这样,文件保护将适用于所有相关文件,而与创建时间无关。