Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

CRUD - 更新 - Swift SDK

項目一覧

  • Realm オブジェクトの更新
  • このページの例について
  • オブジェクトの更新
  • キー値コーディングによるプロパティの更新
  • オブジェクトのアップサート
  • マップ/辞書の更新
  • MutableSet プロパティの更新
  • AnyRealmValue プロパティの更新
  • 埋め込みオブジェクト プロパティの更新
  • 埋め込みオブジェクトの上書き
  • オブジェクトを非同期に更新
  • クラスプロジェクションによるプロパティの更新
  • クラスプロジェクションのプロパティを変更する

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 {
@Persisted var name = ""
@Persisted var age = 0
@Persisted var color = ""
@Persisted var currentCity = ""
@Persisted var citiesVisited: MutableSet<String>
@Persisted var companion: AnyRealmValue
// 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?
}
class Address: EmbeddedObject {
@Persisted var street: String?
@Persisted var city: String?
@Persisted var country: String?
@Persisted 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 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)

割り当てを通じて任意の 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"
}

戻る

読み取り