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

定义 Realm 对象模型 - Swift SDK

在此页面上

  • 定义新对象类型
  • 声明属性
  • 持久化属性
  • Objective-C 动态属性
  • 指定可选/必需属性
  • 指定主键
  • 为属性创建索引
  • 忽略属性
  • 声明枚举属性
  • 重新映射属性名称
  • 定义类投影
  • 关于这些示例
  • 如何定义类投影
  • 定义非对称对象
  • 定义非结构化数据

您可以通过从 RLMObjectRLMEmbeddedObject类派生来定义Realm 对象。 该类的名称将成为域中的表名称,并且该类的属性将在数据库中持久保留。 这样一来,使用持久对象就像使用常规Objective-C对象一样容易。

// A dog has an _id primary key, a string name, an optional
// string breed, and a date of birth.
@interface Dog : RLMObject
@property RLMObjectId *_id;
@property NSString *name;
@property NSString *breed;
@property NSDate *dateOfBirth;
@end
@implementation Dog
+ (NSString *)primaryKey {
return @"_id";
}
+ (NSArray<NSString *> *)requiredProperties {
return @[
@"_id", @"name", @"dateOfBirth"
];
}
@end

你可以通过从 ObjectEmbeddedObject 类派生来定义 Realm 对象。类的名称成为域中的表名称,并且类的属性将在在数据库中持久保留。这样一来,处理持久对象就像处理常规 Swift 对象一样容易。

// A dog has an _id primary key, a string name, an optional
// string breed, and a date of birth.
class Dog: Object {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var name = ""
@Persisted var breed: String?
@Persisted var dateOfBirth = Date()
}

注意

类名不得超过 57 个 UTF-8 字符。

当您声明某个类的属性时,可指定这些属性是否应由 Realm 来管理。Managed properties(托管属性)会在数据库中存储或更新。Ignored properties(已忽略属性)不会存储到数据库中。您可在类中混用托管属性和已忽略属性。

用于将属性标记为托管或已忽略的语法有所不同,具体取决于您使用的 SDK 版本。

10.10.0 版本新增@Persisted 声明样式会替换旧版 SDK 中的 @objc dynamicRealmOptionalRealmProperty 声明符号。有关 SDK 的旧版本,请参阅:Objective-C 动态属性

将要存储到数据库中的模型属性声明为 @Persisted。此举可让它们访问底层数据库数据。

当您在某个类中将所有属性声明为 @Persisted 时,该类中的其他属性会被自动忽略。

如果您在类定义中混用 @Persisted@objc dynamic 属性声明,则会忽略所有标记为 @objc dynamic 的属性。

提示

另请参阅:

支持的属性类型页面包含属性声明速查表。

在版本 10.10.0 中更改:该属性声明信息适用于 10.10.0 之前的 SDK 版本。

在 Objective-C 运行时中声明动态 Realm 模型属性。此举可让它们访问底层数据库数据。

您可以执行以下任一操作:

  • 使用 @objc dynamic var 可声明单个属性。

  • 使用 @objcMembers 可声明一个类。然后,使用 dynamic var 来声明各个属性。

使用 let 来声明 LinkingObjectsListRealmOptionalRealmProperty。Objective-C 运行时无法表示这些通用属性。

10.8.0 版本中的更改RealmProperty 取代了 RealmOptional

提示

另请参阅:

支持的属性类型页面包含属性声明速查表。

提示

有关 Realm 支持将哪些类型用作属性的参考信息,请参阅支持的属性类型

声明非泛型属性时,请使用 @Persisted 注释。@Persisted 属性将 Realm 模型属性转化为底层数据库数据的访问器。

像在普通Objective-C接口上一样声明对象类型的属性。

要在Realm大量中使用您的接口,请将您的接口名称传递给RLM_COLLECTION_TYPE()宏。 您可以将其放在接口头文件的底部。 RLM_COLLECTION_TYPE()宏创建一个协议,允许您使用类型标签RLMArray

// Task.h
@interface Task : RLMObject
@property NSString *description;
@end
// Define an RLMArray<Task> type
RLM_COLLECTION_TYPE(Task)
// User.h
// #include "Task.h"
@interface User : RLMObject
@property NSString *name;
// Use RLMArray<Task> to have a list of tasks
// Note the required double tag (<Task *><Task>)
@property RLMArray<Task *><Task> *tasks;
@end

声明非泛型属性时,请使用@objc dynamic var注解。 @objc dynamic var属性将Realm模型属性转换为根本的数据库数据的访问器。 如果类声明为@objcMembers (Swift 4或更高版本),则可以将属性声明为dynamic var ,而不使用@objc

要声明泛型类型LinkingObjectsListRealmProperty的属性,请使用let 。 泛型属性无法在 Objective C运行时中表示,而Realm使用该运行时来动态调度动态属性。

注意

属性名称不得超过 63 个 UTF-8 字符。

可以使用标准 Swift 语法将属性声明为可选或必需(非可选)。

class Person: Object {
// Required string property
@Persisted var name = ""
// Optional string property
@Persisted var address: String?
// Required numeric property
@Persisted var ageYears = 0
// Optional numeric property
@Persisted var heightCm: Float?
}

要将给定属性声明为必需属性,请实现requiredProperties方法并返回所需属性名称的大量。

@interface Person : RLMObject
// Required property - included in `requiredProperties`
// return value array
@property NSString *name;
// Optional string property - not included in `requiredProperties`
@property NSString *address;
// Required numeric property
@property int ageYears;
// Optional numeric properties use NSNumber tagged
// with RLMInt, RLMFloat, etc.
@property NSNumber<RLMFloat> *heightCm;
@end
@implementation Person
// Specify required pointer-type properties here.
// Implicitly required properties (such as properties
// of primitive types) do not need to be named here.
+ (NSArray<NSString *> *)requiredProperties {
return @[@"name"];
}
@end

10.8.0 版本中的更改RealmProperty 取代了 RealmOptional

您可以使用标准 Swift 语法将StringDateDataObjectId属性声明为可选或必需(非可选)属性。 使用RealmProperty类型声明可选的数字类型。

class Person: Object {
// Required string property
@objc dynamic var name = ""
// Optional string property
@objc dynamic var address: String?
// Required numeric property
@objc dynamic var ageYears = 0
// Optional numeric property
let heightCm = RealmProperty<Float?>()
}

RealmProperty 支持IntFloatDoubleBool以及Int的所有大小版本( Int8Int16Int32Int64 )。

您将某一属性指定为某个类的主键

通过使用主键,您可以高效地查找、更新和更新或插入对象。

主键受到以下限制:

  • 每个对象模型只能定义一个主键。

  • 主键值必须在 Realm 内某一对象的所有实例中保持唯一。如果尝试插入重复的主键值,Realm 会引发错误。

  • 主键值不可变。要更改某一对象的主键值,必须删除原始对象并插入具有其他主键值的新对象。

  • 嵌入式对象无法定义主键。

@Persisted表示法上声明带有primaryKey: true的属性,以设立模型的主键。

class Project: Object {
@Persisted(primaryKey: true) var id = 0
@Persisted var name = ""
}

覆盖+[RLMObject primaryKey]以设立模型的主键。

@interface Project : RLMObject
@property NSInteger id; // Intended primary key
@property NSString *name;
@end
@implementation Project
// Return the name of the primary key property
+ (NSString *)primaryKey {
return @"id";
}
@end

覆盖Object.primaryKey()以设立模型的主键。

class Project: Object {
@objc dynamic var id = 0
@objc dynamic var name = ""
// Return the name of the primary key property
override static func primaryKey() -> String? {
return "id"
}
}

您可对模型的给定属性创建索引。索引会使用相等和 IN 运算符加快查询速度。它们会使插入和更新操作的速度稍稍减慢。索引会占用内存并在 Realm 文件中占用更多空间。每个索引条目至少有 12 个字节。最好只在针对特定情况优化读取性能时添加索引。

Realm 支持为字符串、整数、布尔值、DateUUIDObjectIdAnyRealmValue 属性创建索引。

版本 10.8.0 中的新增功能UUIDAnyRealmValue 类型

要为属性建立索引,请使用@Persisted表示法的indexed:true来声明该属性。

class Book: Object {
@Persisted var priceCents = 0
@Persisted(indexed: true) var title = ""
}

要为属性建立索引,请覆盖+[RLMObject indexedProperties]并返回已建立索引的属性名称列表。

@interface Book : RLMObject
@property int priceCents;
@property NSString *title;
@end
@implementation Book
// Return a list of indexed property names
+ (NSArray *)indexedProperties {
return @[@"title"];
}
@end

要为属性建立索引,请重写Object.indexedProperties()并返回已建立索引的属性名称列表。

class Book: Object {
@objc dynamic var priceCents = 0
@objc dynamic var title = ""
// Return a list of indexed property names
override static func indexedProperties() -> [String] {
return ["title"]
}
}

被忽略属性的行为与普通属性完全相同。它们不能用于查询,也不会触发Realm通知。您仍然可以使用 KVO 观察它们。

提示

Realm 会自动忽略只读属性。

自版本10.10.0起已弃用ignoredProperties()

如果不希望将模型中的一个字段保存到它的 Realm 中,请在属性中保留 @Persisted 符号。

此外,如果您在类中混用 @Persisted@objc dynamic 属性声明,则 @objc dynamic 属性将被忽略。

class Person: Object {
// If some properties are marked as @Persisted,
// any properties that do not have the @Persisted
// annotation are automatically ignored.
var tmpId = 0
// The @Persisted properties are managed
@Persisted var firstName = ""
@Persisted var lastName = ""
// Read-only properties are automatically ignored
var name: String {
return "\(firstName) \(lastName)"
}
// If you mix the pre-10.10 property declaration
// syntax `@objc dynamic` with the 10.10+ @Persisted
// annotation within a class, `@objc dynamic`
// properties are ignored.
@objc dynamic var email = ""
}

如果您不想将模型中的字段保存到其域中,请覆盖+[RLMObjectignoreProperties]并返回被忽略属性名称的列表。

@interface Person : RLMObject
@property NSInteger tmpId;
@property (readonly) NSString *name; // read-only properties are automatically ignored
@property NSString *firstName;
@property NSString *lastName;
@end
@implementation Person
+ (NSArray *)ignoredProperties {
return @[@"tmpId"];
}
- (NSString *)name {
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end

如果您不想将模型中的字段保存到其域中,请重写Object.ignoredProperties()并返回被忽略的属性名称列表。

class Person: Object {
@objc dynamic var tmpId = 0
@objc dynamic var firstName = ""
@objc dynamic var lastName = ""
// Read-only properties are automatically ignored
var name: String {
return "\(firstName) \(lastName)"
}
// Return a list of ignored property names
override static func ignoredProperties() -> [String] {
return ["tmpId"]
}
}

在版本 10.10.0 中进行了更改:协议现在是 PersistableEnum,而不是 RealmEnum

您可以将枚举与@Persisted一起使用,方法是将枚举标记为符合PersistableEnum协议。 PersistableEnum可以是任何原始类型为Realm支持类型的RawRepresentable枚举。

// Define the enum
enum TaskStatusEnum: String, PersistableEnum {
case notStarted
case inProgress
case complete
}
// To use the enum:
class Task: Object {
@Persisted var name: String = ""
@Persisted var owner: String?
// Required enum property
@Persisted var status = TaskStatusEnum.notStarted
// Optional enum property
@Persisted var optionalTaskStatusEnumProperty: TaskStatusEnum?
}

Realm仅支持Int支持的@objc枚举。

// Define the enum
@objc enum TaskStatusEnum: Int, RealmEnum {
case notStarted = 1
case inProgress = 2
case complete = 3
}
// To use the enum:
class Task: Object {
@objc dynamic var name: String = ""
@objc dynamic var owner: String?
// Required enum property
@objc dynamic var status = TaskStatusEnum.notStarted
// Optional enum property
let optionalTaskStatusEnumProperty = RealmProperty<TaskStatusEnum?>()
}

提示

另请参阅:

10.33.0 版本新增

您可以将对象模型中属性的公共名称映射为不同的私有名称以存储在 Realm 中。例如,如果您的 Device Sync 模式属性名称使用蛇形命名法,而您的项目使用 Swift 惯用的驼峰命名法,则您可能需要执行此操作。

将您要在项目中使用的名称声明为针对对象模型的 @Persisted 属性。然后,通过 propertiesMapping() 函数传递包含这些属性名称的公共指和私有值的字典。

在此示例中,firstName 是我们在整个项目的代码中用于执行增删改查操作的公共属性名称。通过使用 propertiesMapping() 函数,可对其进行映射以使用 Realm 中的私有属性名称 first_name 来存储值。如果写入同步 Realm,同步模式则会发现使用私有属性名称 first_name 来存储的这些值。

class Person: Object {
@Persisted var firstName = ""
@Persisted var lastName = ""
override class public func propertiesMapping() -> [String: String] {
["firstName": "first_name",
"lastName": "last_name"]
}
}

本部分的示例使用了一个简易数据集。这两个 Realm 对象类型分别为 Person 和嵌入式对象 AddressPerson 包含名字和姓氏、可选 Address 以及由其他 Person 对象组成的好友列表。Address 则包含城市和国家/地区。

请参阅 PersonAddress 这两个类的模式,如下所示:

class Person: Object {
@Persisted var firstName = ""
@Persisted var lastName = ""
@Persisted var address: Address?
@Persisted var friends = List<Person>()
}
class Address: EmbeddedObject {
@Persisted var city: String = ""
@Persisted var country = ""
}

10.21.0 版新增功能

通过创建 Projection 类型的类来定义类投影。 指定要在类投影中使用其属性的对象嵌入式对象基数。 使用@Projected属性包装器声明您想要从基础对象上的@Persisted属性投影的属性。

注意

在类投影中使用ListMutableSet时,类投影中的类型应为ProjectedCollection。

class PersonProjection: Projection<Person> {
@Projected(\Person.firstName) var firstName // Passthrough from original object
@Projected(\Person.address?.city) var homeCity // Rename and access embedded object property through keypath
@Projected(\Person.friends.projectTo.firstName) var firstFriendsName: ProjectedCollection<String> // Collection mapping
}

定义类投影时,可通过多种方式转换原始 @Persisted 属性:

  • Passthrough(直通):属性的名称和类型均与原始对象相同

  • Rename(重命名):属性的类型与原始对象相同,但名称不同

  • Keypath resolution(键路径解析):使用键路径解析来访问原始对象的属性,其中包括嵌入式对象属性

  • Collection mapping(集合映射):将 ObjectEmbeddedObject列表可变集投影为原始值的集合

  • 排除:当使用类投影时,未通过类投影 @Projected 的底层对象属性将被排除。这样,您将能够监视对类投影的更改,而不会看到对不属于类投影的属性的更改。

10.29.0 版中的新增功能

如果应用程序使用Flexible Sync,您可以使用数据导入将对象从设备单向同步到链接至 Atlas App Services App 的数据库。定义非对称对象的方法是继承 AsymmetricObject。

class WeatherSensor: AsymmetricObject {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var deviceId: String
@Persisted var temperatureInFahrenheit: Float
@Persisted var barometricPressureInHg: Float
@Persisted var windSpeedInMph: Int
}

已在 10.42.4 版中更改:非对称对象可链接到非嵌入式对象。

AsymmetricObject 广泛支持与 Object 相同的属性类型,但存在某些例外情况:

  • 非对称对象只能链接到嵌入式对象
    • ObjectList<Object> 属性在 Swift SDK 10.42.3 及更早版本中不受支持。在 Swift SDK 10.42.4 及更高版本中,非对称对象可链接到非嵌入式对象。

    • EmbeddedObjectList<EmbeddedObject> 均受到支持。

您无法从 Object 内链接到 AsymmetricObject。此操作会引发错误。

非对称对象的运行方式与其他 Realm 对象不同。您无法:

  • 将非对称对象添加到 Realm

  • 从 Realm 中移除非对称对象

  • 查询非对称对象

您只能创建一个非对称对象,然后该对象会单向同步到通过 Device Sync 链接到您应用程序的 Atlas 数据库。

有关更多信息,请参阅:创建非对称对象。

10.51.0版本新增

从 SDK 版本10.51.0开始, 您可以在AnyRealmValue属性中存储混合数据的集合。 您可以使用此功能对复杂的数据结构(例如JSON或MongoDB文档)进行建模,而无需定义严格的数据模型。

非结构化数据是指不容易符合预期模式的数据,因此对单个数据类进行建模很困难或不切实际。 示例,您的应用可能具有高度可变的数据或动态数据,其结构在运行时未知。

将集合存储在混合属性中可在不牺牲功能的情况下提供灵活性,包括使用Device Sync时的性能同步。 您可以像使用非混合集合一样使用它们:

  • 您最多可以嵌套100级混合集合。

  • 您可以对混合集合的React进行查询和响应。

  • 您可以查找并更新单个混合集合元素。

但是,与使用结构化模式或将JSON blob 序列化为单个string属性相比,在混合集合中存储数据的性能较低。

要对应用中的非结构化数据进行建模,请在模式中将相应属性定义为AnyRealmValue类型。 然后,您可以设立这些AnyRealmValue属性设置为AnyRealmValue元素的列表或字典集合。 请注意, AnyRealmValue不能表示MutableSet或嵌入式对象。

提示

  • 当类型未知但每个值都有唯一标识符时,请使用混合数据类型的映射。

  • 当类型未知但对象的顺序有意义时,请使用混合数据类型的列表。

后退

模型数据