CRUD - 更新 - Swift SDK
項目一覧
Realm オブジェクトの更新
Realm オブジェクトへの更新は、書込みトランザクション (write transaction) 内で発生する必要があります。 書込みトランザクション (write transaction) の詳細については、「 トランザクション 」を参照してください。
このページの例について
このページの例では、次のモデルを使用します。
// 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 Dog: Object { var name = "" var age = 0 var color = "" var currentCity = "" var citiesVisited: MutableSet<String> var companion: AnyRealmValue // 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? } class Address: EmbeddedObject { var street: String? var city: String? var country: String? var postalCode: String? }
オブジェクトの更新
書込みトランザクション (write transaction) 内の Realm オブジェクトのプロパティは、他の Swift または Objective-C オブジェクトを更新するのと同じ方法で変更できます。
RLMRealm *realm = [RLMRealm defaultRealm]; // Open a thread-safe transaction. [realm transactionWithBlock:^{ // Get a dog to update. Dog *dog = [[Dog allObjectsInRealm: realm] firstObject]; // Update some properties on the instance. // These changes are saved to the realm. dog.name = @"Wolfie"; dog.age += 1; }];
let realm = try! Realm() // Get a dog to update let dog = realm.objects(Dog.self).first! // Open a thread-safe transaction try! realm.write { // Update some properties on the instance. // These changes are saved to the realm dog.name = "Wolfie" dog.age += 1 }
Tip
関連オブジェクトと埋め込みオブジェクトの更新
埋め込みオブジェクトまたは関連オブジェクトのプロパティを更新するには、通常のネストされたオブジェクトのように ドット表記 または 括弧表記 で プロパティを変更します。
キー値コーディングによるプロパティの更新
Object
、 、Result
はすべてList
キー値コーディング に準拠しています。 。これは、実行時に更新するプロパティを決定する必要がある場合に役立ちます。
コレクションに KVM を適用すると、オブジェクトを一括でアップデートする優れた方法です。 すべてのアイテムのアクセス子を作成しながら、コレクションを反復処理するオーバーヘッドを回避します。
let realm = try! Realm() let allDogs = realm.objects(Dog.self) try! realm.write { allDogs.first?.setValue("Sparky", forKey: "name") // Move the dogs to Toronto for vacation allDogs.setValue("Toronto", forKey: "currentCity") }
この方法で埋め込みオブジェクトまたは関係の値を追加することもできます。 この例では、オブジェクトのリスト プロパティにコレクションを追加します。
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock:^() { // Create a person to take care of some dogs. Person *ali = [[Person alloc] initWithValue:@{@"_id": @1, @"name": @"Ali"}]; [realm addObject:ali]; // Find dogs younger than 2. RLMResults<Dog *> *puppies = [Dog objectsInRealm:realm where:@"age < 2"]; // Batch update: give all puppies to Ali. [ali setValue:puppies forKey:@"dogs"]; }];
let realm = try! Realm() try! realm.write { // Create a person to take care of some dogs. let person = Person(value: ["id": 1, "name": "Ali"]) realm.add(person) let dog = Dog(value: ["name": "Rex", "age": 1]) realm.add(dog) // Find dogs younger than 2. let puppies = realm.objects(Dog.self).filter("age < 2") // Give all puppies to Ali. person.setValue(puppies, forKey: "dogs") }
オブジェクトのアップサート
アップサートは、オブジェクトがすでに存在するかどうかに応じて、オブジェクトを挿入または更新します。 アップサートにはプライマリキーが必要です。
オブジェクトをアップサートするには、 -[RMRealm addOrUpdateObject:] を呼び出します。
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock:^{ Person *jones = [[Person alloc] initWithValue:@{@"_id": @1234, @"name": @"Jones"}]; // Add a new person to the realm. Since nobody with ID 1234 // has been added yet, this adds the instance to the realm. [realm addOrUpdateObject:jones]; Person *bowie = [[Person alloc] initWithValue:@{@"_id": @1234, @"name": @"Bowie"}]; // Judging by the ID, it's the same person, just with a different name. // This overwrites the original entry (i.e. Jones -> Bowie). [realm addOrUpdateObject:bowie]; }];
オブジェクトをアップサートするには、2 つ目のパラメータである更新ポリシーを.modified
に設定して、 Realm.add(_:update:)を呼び出します。
let realm = try! Realm() try! realm.write { let person1 = Person(value: ["id": 1234, "name": "Jones"]) // Add a new person to the realm. Since nobody with ID 1234 // has been added yet, this adds the instance to the realm. realm.add(person1, update: .modified) let person2 = Person(value: ["id": 1234, "name": "Bowie"]) // Judging by the ID, it's the same person, just with a // different name. When `update` is: // - .modified: update the fields that have changed. // - .all: replace all of the fields regardless of // whether they've changed. // - .error: throw an exception if a key with the same // primary key already exists. realm.add(person2, update: .modified) }
また、プライマリキーと更新対象の値のサブセットを渡して、オブジェクトを部分的に更新することもできます。
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock:^{ // Only update the provided values. // Note that the "name" property will remain the same // for the person with primary key "_id" 123. [Person createOrUpdateModifiedInRealm:realm withValue:@{@"_id": @123, @"dogs": @[@[@"Buster", @5]]}]; }];
let realm = try! Realm() try! realm.write { // Use .modified to only update the provided values. // Note that the "name" property will remain the same // for the person with primary key "id" 123. realm.create(Person.self, value: ["id": 123, "dogs": [["Buster", 5]]], update: .modified) }
マップ/辞書の更新
Realm マップ は標準の 辞書 と同様に更新できます。
let realm = try! Realm() // Find the dog we want to update let wolfie = realm.objects(Dog.self).where { $0.name == "Wolfie" }.first! print("Wolfie's favorite park in New York is: \(wolfie.favoriteParksByCity["New York"])") XCTAssertTrue(wolfie.favoriteParksByCity["New York"] == "Domino Park") // Update values for keys, or add values if the keys do not currently exist try! realm.write { wolfie.favoriteParksByCity["New York"] = "Washington Square Park" wolfie.favoriteParksByCity.updateValue("A Street Park", forKey: "Boston") wolfie.favoriteParksByCity.setValue("Little Long Pond", forKey: "Seal Harbor") } XCTAssertTrue(wolfie.favoriteParksByCity["New York"] == "Washington Square Park")
MutableSet プロパティの更新
書き込みトランザクション中にこれらの要素を MutableSet insert
追加して、 プロパティに追加することができます。 複数のセットを操作している場合は、あるセットに含まれるセット要素をもう 1 つのセットから挿入または削除することもできます。 あるいは、セットを変更して、両方の共通要素のみを含むようにすることもできます。
let realm = try! Realm() // Record a dog's name, current city, and store it to the cities visited. let dog = Dog() dog.name = "Maui" dog.currentCity = "New York" try! realm.write { realm.add(dog) dog.citiesVisited.insert(dog.currentCity) } // Update the dog's current city, and add it to the set of cities visited. try! realm.write { dog.currentCity = "Toronto" dog.citiesVisited.insert(dog.currentCity) } XCTAssertEqual(dog.citiesVisited.count, 2) // If you're operating with two sets, you can insert the elements from one set into another set. // The dog2 set contains one element that isn't present in the dog set. try! realm.write { dog.citiesVisited.formUnion(dog2.citiesVisited) } XCTAssertEqual(dog.citiesVisited.count, 3) // Or you can remove elements that are present in the second set. This removes the one element // that we added above from the dog2 set. try! realm.write { dog.citiesVisited.subtract(dog2.citiesVisited) } XCTAssertEqual(dog.citiesVisited.count, 2) // If the sets contain common elements, you can mutate the set to only contain those common elements. // In this case, the two sets contain no common elements, so this set should now contain 0 items. try! realm.write { dog.citiesVisited.formIntersection(dog2.citiesVisited) } XCTAssertEqual(dog.citiesVisited.count, 0)
AnyRealmValue プロパティの更新
割り当てを通じて任意の RealmValue プロパティを更新できますが、割り当てるときに値のタイプを指定する必要があります。 Realm Swift SDK は、AnyRealmValue が保存できるすべてのタイプを反復処理するAnyRealmValue 列挙型を提供します。
let realm = try! Realm() // Get a dog to update let rex = realm.objects(Dog.self).where { $0.name == "Rex" }.first! try! realm.write { // As with creating an object with an AnyRealmValue, you must specify the // type of the value when you update the property. rex.companion = .object(Dog(value: ["name": "Regina"])) }
埋め込みオブジェクト プロパティの更新
埋め込みオブジェクト内のプロパティを更新するには、書込みトランザクション内のプロパティを変更します。 埋め込みオブジェクトが null の場合、埋め込みオブジェクトのプロパティを更新しても効果はありません。
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock: ^{ Contact *contact = [Contact objectInRealm:realm forPrimaryKey:[[RLMObjectId alloc] initWithString:@"5f481c21f634a1f4eeaa7268" error:nil]]; contact.address.street = @"Hollywood Upstairs Medical College"; contact.address.city = @"Los Angeles"; contact.address.postalCode = @"90210"; NSLog(@"Updated contact: %@", contact); }];
// Open the default realm let realm = try! Realm() let idOfPersonToUpdate = 123 // Find the person to update by ID guard let person = realm.object(ofType: Person.self, forPrimaryKey: idOfPersonToUpdate) else { print("Person \(idOfPersonToUpdate) not found") return } try! realm.write { // Update the embedded object directly through the person // If the embedded object is null, updating these properties has no effect person.address?.street = "789 Any Street" person.address?.city = "Anytown" person.address?.postalCode = "12345" print("Updated person: \(person)") }
埋め込みオブジェクトの上書き
埋め込みオブジェクトを上書きするには、書込みトランザクション(write transaction)で、パーティの埋め込みオブジェクト プロパティを新しい インスタンスに再割り当てします。
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock: ^{ Contact *contact = [Contact objectInRealm:realm forPrimaryKey:[[RLMObjectId alloc] initWithString:@"5f481c21f634a1f4eeaa7268" error:nil]]; Address *newAddress = [[Address alloc] init]; newAddress.street = @"Hollywood Upstairs Medical College"; newAddress.city = @"Los Angeles"; newAddress.country = @"USA"; newAddress.postalCode = @"90210"; contact.address = newAddress; NSLog(@"Updated contact: %@", contact); }];
// Open the default realm let realm = try! Realm() let idOfPersonToUpdate = 123 // Find the person to update by ID guard let person = realm.object(ofType: Person.self, forPrimaryKey: idOfPersonToUpdate) else { print("Person \(idOfPersonToUpdate) not found") return } try! realm.write { let newAddress = Address() newAddress.street = "789 Any Street" newAddress.city = "Anytown" newAddress.country = "USA" newAddress.postalCode = "12345" // Overwrite the embedded object person.address = newAddress print("Updated person: \(person)") }
オブジェクトを非同期に更新
Swift の同時実行機能を使用すると、アクター分離された Realm を使用してオブジェクトを非同期に更新できます。
RealmActor
Use Realm with Atlas で定義された例の] 関数は、アクター分離された Realm 内のオブジェクトを更新する方法を示しています。
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) } }
そして、Swift の非同期構文を使用してこの更新を実行できます。
let actor = try await RealmActor() // Read objects in functions isolated to the actor and pass primitive values to the caller func getObjectId(in actor: isolated RealmActor, forTodoNamed name: String) async -> ObjectId { let todo = actor.realm.objects(Todo.self).where { $0.name == name }.first! return todo._id } let objectId = await getObjectId(in: actor, forTodoNamed: "Keep it safe") try await actor.updateTodo(_id: objectId, name: "Keep it safe", owner: "Frodo", status: "Completed")
この操作は、呼び出し元のスレッドでブロックされたり I/O が実行されたりすることはありません。 Swift 同時実行機能を使用して Realm への書き込みを実行する方法の詳細については、 「 アクターで Realm を使用する - Swift SDK 」を参照してください。
クラスプロジェクションによるプロパティの更新
クラスプロジェクションのプロパティを変更する
書込みトランザクション (write transaction) 内で、クラスプロジェクションのプロパティを変更できます。
// Retrieve all class projections of the given type `PersonProjection` // and filter for the first class projection where the `firstName` property // value is "Jason" let person = realm.objects(PersonProjection.self).first(where: { $0.firstName == "Jason" })! // Update class projection property in a write transaction try! realm.write { person.firstName = "David" }