增删改查 - 创建 - Swift SDK
在此页面上
创建新对象
关于本页中的示例
本页中的示例使用以下模型:
// 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 { var name = "" } class Dog: Object { var name = "" var age = 0 var color = "" var currentCity = "" var citiesVisited: MutableSet<String> var companion: AnyRealmValue // To-one relationship var favoriteToy: DogToy? // Map of city name -> favorite park in that city var favoriteParksByCity: Map<String, String> } class Person: Object { true) var id = 0 (primaryKey: var name = "" // To-many relationship - a person can have many dogs var dogs: List<Dog> // Embed a single object. // Embedded object properties must be marked optional. var address: Address? convenience init(name: String, address: Address) { self.init() self.name = name self.address = address } } class Address: EmbeddedObject { var street: String? var city: String? var country: String? 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 属性来实例化一个对象,但只能在写事务中设置该属性的值。除非在写事务中执行操作,否则无法使用该属性的值来初始化对象。
使用 JSON 创建对象
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 属性名称和类型必须与目标对象模式完全匹配。例如:
float
属性必须使用支持浮点数的NSNumbers
来进行初始化。Date
和Data
属性无法通过字符串进行推断。请将它们转换为适当类型后再传给 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"
创建具有 MutableSet 属性的对象
您可以像创建任何 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 属性的对象
在创建具有 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、将其添加到域中或从域中移除,也无法对其进行查询。
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
要将对象从一个域复制到另一个 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
方法不支持处理循环对象图。请勿传入包含涉及直接或间接引用父对象的关系的对象。