定义 Realm 对象模型 - Swift SDK
在此页面上
定义新对象类型
您可以通过从 RLMObject或RLMEmbeddedObject类派生来定义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
你可以通过从 Object 或 EmbeddedObject 类派生来定义 Realm 对象。类的名称成为域中的表名称,并且类的属性将在在数据库中持久保留。这样一来,处理持久对象就像处理常规 Swift 对象一样容易。
// A dog has an _id primary key, a string name, an optional // string breed, and a date of birth. class Dog: Object { true) var _id: ObjectId (primaryKey: var name = "" var breed: String? var dateOfBirth = Date() }
注意
类名不得超过 57 个 UTF-8 字符。
声明属性
当您声明某个类的属性时,可指定这些属性是否应由 Realm 来管理。Managed properties(托管属性)会在数据库中存储或更新。Ignored properties(已忽略属性)不会存储到数据库中。您可在类中混用托管属性和已忽略属性。
用于将属性标记为托管或已忽略的语法有所不同,具体取决于您使用的 SDK 版本。
持久化属性
10.10.0 版本新增:@Persisted
声明样式会替换旧版 SDK 中的 @objc dynamic
、RealmOptional
和 RealmProperty
声明符号。有关 SDK 的旧版本,请参阅:Objective-C 动态属性。
将要存储到数据库中的模型属性声明为 @Persisted
。此举可让它们访问底层数据库数据。
当您在某个类中将所有属性声明为 @Persisted
时,该类中的其他属性会被自动忽略。
如果您在类定义中混用 @Persisted
和 @objc dynamic
属性声明,则会忽略所有标记为 @objc dynamic
的属性。
Objective-C 动态属性
在版本 10.10.0 中更改:该属性声明信息适用于 10.10.0 之前的 SDK 版本。
在 Objective-C 运行时中声明动态 Realm 模型属性。此举可让它们访问底层数据库数据。
您可以执行以下任一操作:
使用
@objc dynamic var
可声明单个属性。使用
@objcMembers
可声明一个类。然后,使用dynamic var
来声明各个属性。
使用 let
来声明 LinkingObjects
、List
、RealmOptional
和 RealmProperty
。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
。
要声明泛型类型LinkingObjects
、 List
和RealmProperty
的属性,请使用let
。 泛型属性无法在 Objective C运行时中表示,而Realm使用该运行时来动态调度动态属性。
注意
属性名称不得超过 63 个 UTF-8 字符。
指定可选/必需属性
可以使用标准 Swift 语法将属性声明为可选或必需(非可选)。
class Person: Object { // Required string property var name = "" // Optional string property var address: String? // Required numeric property var ageYears = 0 // Optional numeric property 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 语法将String
、 Date
、 Data
和ObjectId属性声明为可选或必需(非可选)属性。 使用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 支持Int
、 Float
、 Double
、 Bool
以及Int
的所有大小版本( Int8
、 Int16
、 Int32
、 Int64
)。
指定主键
您将某一属性指定为某个类的主键。
主键受到以下限制:
每个对象模型只能定义一个主键。
主键值必须在 Realm 内某一对象的所有实例中保持唯一。如果尝试插入重复的主键值,Realm 会引发错误。
主键值不可变。要更改某一对象的主键值,必须删除原始对象并插入具有其他主键值的新对象。
嵌入式对象无法定义主键。
在@Persisted
表示法上声明带有primaryKey: true的属性,以设立模型的主键。
class Project: Object { true) var id = 0 (primaryKey: 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 支持为字符串、整数、布尔值、Date
、UUID
、ObjectId
和 AnyRealmValue
属性创建索引。
版本 10.8.0 中的新增功能:UUID
和 AnyRealmValue
类型
要为属性建立索引,请使用@Persisted
表示法的indexed:true来声明该属性。
class Book: Object { var priceCents = 0 true) var title = "" (indexed: }
要为属性建立索引,请覆盖+[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 var firstName = "" 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 { var name: String = "" var owner: String? // Required enum property var status = TaskStatusEnum.notStarted // Optional enum property 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 { var firstName = "" var lastName = "" override class public func propertiesMapping() -> [String: String] { ["firstName": "first_name", "lastName": "last_name"] } }
定义类投影
关于这些示例
本部分的示例使用了一个简易数据集。这两个 Realm 对象类型分别为 Person
和嵌入式对象 Address
。Person
包含名字和姓氏、可选 Address
以及由其他 Person
对象组成的好友列表。Address
则包含城市和国家/地区。
请参阅 Person
和 Address
这两个类的模式,如下所示:
class Person: Object { var firstName = "" var lastName = "" var address: Address? var friends = List<Person>() } class Address: EmbeddedObject { var city: String = "" var country = "" }
如何定义类投影
10.21.0 版新增功能。
通过创建 Projection 类型的类来定义类投影。 指定要在类投影中使用其属性的对象或嵌入式对象基数。 使用@Projected
属性包装器声明您想要从基础对象上的@Persisted
属性投影的属性。
注意
在类投影中使用List或MutableSet时,类投影中的类型应为ProjectedCollection。
class PersonProjection: Projection<Person> { Person.firstName) var firstName // Passthrough from original object (\ Person.address?.city) var homeCity // Rename and access embedded object property through keypath (\ Person.friends.projectTo.firstName) var firstFriendsName: ProjectedCollection<String> // Collection mapping (\}
定义类投影时,可通过多种方式转换原始 @Persisted
属性:
定义非对称对象
10.29.0 版中的新增功能。
如果应用程序使用Flexible Sync,您可以使用数据导入将对象从设备单向同步到链接至 Atlas App Services App 的数据库。定义非对称对象的方法是继承 AsymmetricObject。
class WeatherSensor: AsymmetricObject { true) var _id: ObjectId (primaryKey: var deviceId: String var temperatureInFahrenheit: Float var barometricPressureInHg: Float var windSpeedInMph: Int }
已在 10.42.4 版中更改:非对称对象可链接到非嵌入式对象。
AsymmetricObject
广泛支持与 Object
相同的属性类型,但存在某些例外情况:
- 非对称对象只能链接到嵌入式对象
Object
和List<Object>
属性在 Swift SDK 10.42.3 及更早版本中不受支持。在 Swift SDK 10.42.4 及更高版本中,非对称对象可链接到非嵌入式对象。EmbeddedObject
和List<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
或嵌入式对象。
提示
当类型未知但每个值都有唯一标识符时,请使用混合数据类型的映射。
当类型未知但对象的顺序有意义时,请使用混合数据类型的列表。