Docs 菜单
Docs 主页
/ /
Atlas Device SDKs
/ /

配置并打开 Realm - Swift SDK

在此页面上

  • 在没有同步的情况下开启 Realm
  • 打开默认 Realm 或通过文件 URL 打开 Realm
  • 打开内存中 Realm
  • 使用 Swift 并发功能打开 Realm
  • 关闭 Realm
  • 处理访问 Realm 时出现的错误
  • 向 Realm 提供类的子集
  • 使用 Realm API 初始化属性
  • 在设备锁定时使用 Realm

打开 Realm 时,可以传递 Realm.Configuration ,其中指定有关如何配置 Realm 文件的其他详细信息。这包括:

  • 传递 FileURL 或内存标识符以自定义该 Realm 在设备上的存储方式

  • 提供已登录用户和 Sync 详细信息,以将 Sync 与 Realm 一起使用

  • 指定 Realm 仅使用应用的部分类

  • 是否以及何时压缩 Realm 以减小其文件大小

  • 传递加密密钥以加密 Realm

  • 执行模式更改时提供模式版本或迁移区块

提示

另请参阅:

本页介绍如何打开不同步数据的 Realm 文件。如果您想使用 Device Sync 与其他设备同步数据,请参阅配置和打开 Synced Realm。

您可以使用以下几种不同的配置选项来打开未同步的本地 Realm:

  • 无配置 - 即默认认配置

  • 指定 Realm 的文件 URL

  • 仅在内存中打开 Realm,而不将文件保存到文件系统

  • 复制已同步的 Realm 以便在不使用同步的情况下使用

您可以使用+[RLMRealm defaultRealm] 打开默认 Realm。

您还可以将RLMRealmConfiguration对象传递给+[RLMRealm realmWithConfiguration:error:] ,以在特定文件 URL、内存中或使用Device Sync 打开 Realm。

您可以通过将 RLMRealmConfiguration 实例传递给+[RLMRealmConfiguration setDefaultConfiguration:] 来设置默认 Realm 配置。

// 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)

已在 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 的异步/等待语法打开 Mainactor 隔离的 Realm,或者在异步打开 Realm 时指定一个 actor:

@MainActor
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
@globalActor actor BackgroundActor: GlobalActor {
static var shared = BackgroundActor()
}
@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)")
}
@MainActor
func mainThreadFunction() async throws {
try await backgroundThreadFunction()
}

有关使用 actor 隔离的 Realm 的更多信息,请参阅结合使用 Realm 与 Actor - Swift SDK。

在 Swift 或 Objective-C 中无需手动关闭 Realm。 当 Realm 超出范围并由于 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
}

提示

在低内存限制下运行

某些应用程序(例如 watchOS 应用和 iOS 应用扩展)对其内存占用有严格的限制。要针对低内存环境优化数据模型,请使用类的子集打开 Realm。

默认情况下,Swift SDK 会自动将可执行文件中的所有RLMObjectRLMEmbeddedObject派生类添加到 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 模式中。您可以通过设置 Realm.Configuration 对象的 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 进行初始化。例如:

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 之前已正确设置。

默认情况下,每当设备锁定时,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 可以随时创建和删除辅助文件。不必降低每个文件的保护级别,而是将此操作应用于父文件夹。这样,文件保护将适用于所有相关文件,而与创建时间无关。

提示

另请参阅:

后退

Realm 文件