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

增删改查 - 创建 - Swift SDK

在此页面上

  • 创建新对象
  • 关于本页中的示例
  • 创建对象
  • 使用值初始化对象
  • 使用 JSON 创建对象
  • 创建嵌入式对象
  • 创建具有映射属性的对象
  • 创建具有 MutableSet 属性的对象
  • 创建具有 AnyRealmValue 属性的对象
  • 异步创建对象
  • 创建非对称对象
  • 将对象复制到另一个 Realm

本页中的示例使用以下模型:

// DogToy.h
@interface DogToy : RLMObject
@property NSString *name;
@end
// Dog.h
@interface Dog : RLMObject
@property NSString *name;
@property int age;
@property NSString *color;
// To-one relationship
@property DogToy *favoriteToy;
@end
// Enable Dog for use in RLMArray
RLM_COLLECTION_TYPE(Dog)
// Person.h
// A person has a primary key ID, a collection of dogs, and can be a member of multiple clubs.
@interface Person : RLMObject
@property int _id;
@property NSString *name;
// To-many relationship - a person can have many dogs
@property RLMArray<Dog *><Dog> *dogs;
// Inverse relationship - a person can be a member of many clubs
@property (readonly) RLMLinkingObjects *clubs;
@end
RLM_COLLECTION_TYPE(Person)
// DogClub.h
@interface DogClub : RLMObject
@property NSString *name;
@property RLMArray<Person *><Person> *members;
@end
// Dog.m
@implementation Dog
@end
// DogToy.m
@implementation DogToy
@end
// Person.m
@implementation Person
// Define the primary key for the class
+ (NSString *)primaryKey {
return @"_id";
}
// Define the inverse relationship to dog clubs
+ (NSDictionary *)linkingObjectsProperties {
return @{
@"clubs": [RLMPropertyDescriptor descriptorWithClass:DogClub.class propertyName:@"members"],
};
}
@end
// DogClub.m
@implementation DogClub
@end
class DogToy: Object {
@Persisted var name = ""
}
class Dog: Object {
@Persisted var name = ""
@Persisted var age = 0
@Persisted var color = ""
@Persisted var currentCity = ""
@Persisted var citiesVisited: MutableSet<String>
@Persisted var companion: AnyRealmValue
// To-one relationship
@Persisted var favoriteToy: DogToy?
// Map of city name -> favorite park in that city
@Persisted var favoriteParksByCity: Map<String, String>
}
class Person: Object {
@Persisted(primaryKey: true) var id = 0
@Persisted var name = ""
// To-many relationship - a person can have many dogs
@Persisted var dogs: List<Dog>
// Embed a single object.
// Embedded object properties must be marked optional.
@Persisted var address: Address?
convenience init(name: String, address: Address) {
self.init()
self.name = name
self.address = address
}
}
class Address: EmbeddedObject {
@Persisted var street: String?
@Persisted var city: String?
@Persisted var country: String?
@Persisted var postalCode: String?
}

要将对象添加到域,请像实例化任何其他对象一样实例化该对象,然后将其传递给写事务(write transaction)内的 -[RLMKRealm addObject:]

// Get the default realm.
// You only need to do this once per thread.
RLMRealm *realm = [RLMRealm defaultRealm];
// Instantiate the class.
Dog *dog = [[Dog alloc] init];
dog.name = @"Max";
dog.age = 5;
// Open a thread-safe transaction.
[realm transactionWithBlock:^() {
// Add the instance to the realm.
[realm addObject:dog];
}];

要将一个对象添加到域,请像对待任何其他对象那样将它实例化,然后将它传递给一个写事务内部的 Realm.add(_:update:)

// Instantiate the class and set its values.
let dog = Dog()
dog.name = "Rex"
dog.age = 10
// Get the default realm. You only need to do this once per thread.
let realm = try! Realm()
// Open a thread-safe transaction.
try! realm.write {
// Add the instance to the realm.
realm.add(dog)
}

您可以通过将初始化值传递给 Object.init(value:) 来初始化对象。初始化值可以是 键值编码 兼容对象、字典或大量,其中每个托管属性都有一个元素。

注意

使用数组作为初始化值时,必须按照模型中定义的顺序包含所有属性。

// (1) Create a Dog object from a dictionary
Dog *myDog = [[Dog alloc] initWithValue:@{@"name" : @"Pluto", @"age" : @3}];
// (2) Create a Dog object from an array
Dog *myOtherDog = [[Dog alloc] initWithValue:@[@"Pluto", @3]];
RLMRealm *realm = [RLMRealm defaultRealm];
// Add to the realm with transaction
[realm transactionWithBlock:^() {
[realm addObject:myDog];
[realm addObject:myOtherDog];
}];
// (1) Create a Dog object from a dictionary
let myDog = Dog(value: ["name": "Pluto", "age": 3])
// (2) Create a Dog object from an array
let myOtherDog = Dog(value: ["Fido", 5])
let realm = try! Realm()
// Add to the realm inside a transaction
try! realm.write {
realm.add([myDog, myOtherDog])
}

您甚至可以通过嵌套初始化值来初始化相关嵌入式对象

// Instead of using pre-existing dogs...
Person *aPerson = [[Person alloc]
initWithValue:@[@123, @"Jane", @[aDog, anotherDog]]];
// ...we can create them inline
Person *anotherPerson = [[Person alloc]
initWithValue:@[@123, @"Jane", @[@[@"Buster", @5], @[@"Buddy", @6]]]];
// Instead of using pre-existing dogs...
let aPerson = Person(value: [123, "Jane", [aDog, anotherDog]])
// ...we can create them inline
let anotherPerson = Person(value: [123, "Jane", [["Buster", 5], ["Buddy", 6]]])

某些属性类型只能在写事务中进行更改。例如,您可以使用 MutableSet 属性来实例化一个对象,但只能在写事务中设置该属性的值。除非在写事务中执行操作,否则无法使用该属性的值来初始化对象。

Realm不直接支持JSON,但您可以使用 JSONSerialization.jsonObject(with:options:) 将JSON转换为可以传递给 Realm.create(_:value: 更新:) 的值。

// Specify a dog toy in JSON
NSData *data = [@"{\"name\": \"Tennis ball\"}" dataUsingEncoding: NSUTF8StringEncoding];
RLMRealm *realm = [RLMRealm defaultRealm];
// Insert from NSData containing JSON
[realm transactionWithBlock:^{
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
[DogToy createInRealm:realm withValue:json];
}];
// Specify a dog toy in JSON
let data = "{\"name\": \"Tennis ball\"}".data(using: .utf8)!
let realm = try! Realm()
// Insert from data containing JSON
try! realm.write {
let json = try! JSONSerialization.jsonObject(with: data, options: [])
realm.create(DogToy.self, value: json)
}

JSON 中的嵌套对象或数组映射为一对一一对多的关系。

JSON 属性名称和类型必须与目标对象模式完全匹配。例如:

  • float 属性必须使用支持浮点数的 NSNumbers 来进行初始化。

  • DateData 属性无法通过字符串进行推断。请将它们转换为适当类型后再传给 Realm.create(_:value:update:)。

  • JSON 中的必需属性不能为 null,也不可缺失。

Realm 会忽略 JSON 中未在对象模式中定义的任何属性。

提示

如果您的 JSON schema与您的 Realm 对象不完全一致,请考虑使用第三方框架来转换您的 JSON。有许多模型映射框架可与 Realm 配合使用。请参阅 realm-swift 存储库中的部分列表。

要创建嵌入式对象,请将嵌入式对象的实例分配给父对象的属性:

RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
Address *address = [[Address alloc] init];
address.street = @"123 Fake St.";
address.city = @"Springfield";
address.country = @"USA";
address.postalCode = @"90710";
Contact *contact = [Contact contactWithName:@"Nick Riviera"];
// Assign the embedded object property
contact.address = address;
[realm addObject:contact];
NSLog(@"Added contact: %@", contact);
}];
// Open the default realm
let realm = try! Realm()
try! realm.write {
let address = Address()
address.street = "123 Fake St"
address.city = "Springfield"
address.country = "USA"
address.postalCode = "90710"
let contact = Person(name: "Nick Riviera", address: address)
realm.add(contact)
}

创建具有映射属性的对象时,可以通过以下几种方法来设置键的值:

  • 在对象上设置键和值,然后将对象添加到 Realm

  • 直接在写事务中设置对象的键和值

  • 使用键值编码在写事务中设置或更新键和值

let realm = try! Realm()
// Record a dog's name and current city
let dog = Dog()
dog.name = "Wolfie"
dog.currentCity = "New York"
// Set map values
dog.favoriteParksByCity["New York"] = "Domino Park"
// Store the data in a realm
try! realm.write {
realm.add(dog)
// You can also set map values inside a write transaction
dog.favoriteParksByCity["Chicago"] = "Wiggly Field"
dog.favoriteParksByCity.setValue("Bush Park", forKey: "Ottawa")
}

Realm 不允许在映射键中使用 .$ 字符。您可以使用百分比编码和解码来存储包含这些不允许的任一字符的映射键。

// Percent encode . or $ characters to use them in map keys
let mapKey = "New York.Brooklyn"
let encodedMapKey = "New York%2EBrooklyn"

您可以像创建任何 Realm 对象一样来创建包含 MutableSet 属性的对象,但您只能在写事务中更改 MutableSet。这意味着您只能在写事务中设置可变集属性的值。

let realm = try! Realm()
// Record a dog's name and current city
let dog = Dog()
dog.name = "Maui"
dog.currentCity = "New York"
// Store the data in a realm. Add the dog's current city
// to the citiesVisited MutableSet
try! realm.write {
realm.add(dog)
// You can only mutate the MutableSet in a write transaction.
// This means you can't set values at initialization, but must do it during a write.
dog.citiesVisited.insert(dog.currentCity)
}
// You can also add multiple items to the set.
try! realm.write {
dog.citiesVisited.insert(objectsIn: ["Boston", "Chicago"])
}
print("\(dog.name) has visited: \(dog.citiesVisited)")

在创建具有 AnyRealmValue 属性的对象时,您必须指定存储在该属性中的值的类型。Realm Swift SDK 提供了一个 AnyRealmValue 枚举,它可以遍历 AnyRealmValue 可以存储的所有类型。

随后,当读取 AnyRealmValue 时,您必须先检查类型,然后再对该值进行任何操作。

// Create a Dog object and then set its properties
let myDog = Dog()
myDog.name = "Rex"
// This dog has no companion.
// You can set the field's type to "none", which represents `nil`
myDog.companion = .none
// Create another Dog whose companion is a cat.
// We don't have a Cat object, so we'll use a string to describe the companion.
let theirDog = Dog()
theirDog.name = "Wolfie"
theirDog.companion = .string("Fluffy the Cat")
// Another dog might have a dog as a companion.
// We do have an object that can represent that, so we can specify the
// type is a Dog object, and even set the object's value.
let anotherDog = Dog()
anotherDog.name = "Fido"
// Note: this sets Spot as a companion of Fido, but does not set
// Fido as a companion of Spot. Spot has no companion in this instance.
anotherDog.companion = .object(Dog(value: ["name": "Spot"]))
// Add the dogs to the realm
let realm = try! Realm()
try! realm.write {
realm.add([myDog, theirDog, anotherDog])
}
// After adding these dogs to the realm, we now have 4 dog objects.
let dogs = realm.objects(Dog.self)
XCTAssertEqual(dogs.count, 4)

你可以使用 Swift 并发功能来异步写入 actor 隔离的领域。

这个函数来自“结合使用 Realm 与 Actor”页面中给出的示例 RealmActor 中的函数,显示了如何写入 actor 隔离的 Realm:

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
])
}
}

您可以使用 Swift 的异步语法来执行此写入:

func createObject() async throws {
// Because this function is not isolated to this actor,
// you must await operations completed on the actor
try await actor.createTodo(name: "Take the ring to Mount Doom", owner: "Frodo", status: "In Progress")
let taskCount = await actor.count
print("The actor currently has \(taskCount) tasks")
}
let actor = try await RealmActor()
try await createObject()

此操作不会阻塞调用线程或在调用线程上执行 I/O。有关使用 Swift 并发功能写入 Realm 的更多信息,请参阅结合使用 Realm 与 Actor - Swift SDK

10.29.0 版中的新增功能

您只能使用 create(_ type:, value:) 来创建 AsymmetricObject。当您创建 AsymmetricObject 时,它会通过数据导入单向同步到链接到您的 Atlas App Services App 的 Atlas 数据库。您无法在本地访问 AsymmetricObject、将其添加到域中或从域中移除,也无法对其进行查询。

@MainActor
func useRealm(_ asymmetricRealm: Realm, _ user: User) async {
try! asymmetricRealm.write {
asymmetricRealm.create(WeatherSensor.self,
value: [ "_id": ObjectId.generate(),
"deviceId": "WX1278UIT",
"temperatureInFahrenheit": 66.7,
"barometricPressureInHg": 29.65,
"windSpeedInMph": 2
])
}
}

您可以为使用Flexible Sync 配置初始化的域创建 AsymmetricObject。 有关更多信息,请参阅:打开同步Realm以进行 Flexible Sync。

要将对象从一个域复制到另一个 Realm,请将原始对象传递给+[RLMObject createInRealm:withValue:]:

RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.inMemoryIdentifier = @"first realm";
RLMRealm *realm = [RLMRealm realmWithConfiguration:configuration error:nil];
[realm transactionWithBlock:^{
Dog *dog = [[Dog alloc] init];
dog.name = @"Wolfie";
dog.age = 1;
[realm addObject:dog];
}];
// Later, fetch the instance we want to copy
Dog *wolfie = [[Dog objectsInRealm:realm where:@"name == 'Wolfie'"] firstObject];
// Open the other realm
RLMRealmConfiguration *otherConfiguration = [RLMRealmConfiguration defaultConfiguration];
otherConfiguration.inMemoryIdentifier = @"second realm";
RLMRealm *otherRealm = [RLMRealm realmWithConfiguration:otherConfiguration error:nil];
[otherRealm transactionWithBlock:^{
// Copy to the other realm
Dog *wolfieCopy = [[wolfie class] createInRealm:otherRealm withValue:wolfie];
wolfieCopy.age = 2;
// Verify that the copy is separate from the original
XCTAssertNotEqual(wolfie.age, wolfieCopy.age);
}];

要将对象从一个 Realm 复制到另一个 Realm,请将原始对象传递给Realm.create(_:value:update:)::

let realm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "first realm"))
try! realm.write {
let dog = Dog()
dog.name = "Wolfie"
dog.age = 1
realm.add(dog)
}
// Later, fetch the instance we want to copy
let wolfie = realm.objects(Dog.self).first(where: { $0.name == "Wolfie" })!
// Open the other realm
let otherRealm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "second realm"))
try! otherRealm.write {
// Copy to the other realm
let wolfieCopy = otherRealm.create(type(of: wolfie), value: wolfie)
wolfieCopy.age = 2
// Verify that the copy is separate from the original
XCTAssertNotEqual(wolfie.age, wolfieCopy.age)
}

重要

create 方法不支持处理循环对象图。请勿传入包含涉及直接或间接引用父对象的关系的对象。

后退

CRUD