๋ฐ์ดํฐ ์ฐ๊ธฐ - SwiftUI
์ด ํ์ด์ง์ ๋ด์ฉ
๋น ๋ฅธ ์ฐ๊ธฐ ์ํ
ํธ๋์ญ์ ๋ธ๋ก ๋ด์์ ์ฐ๊ธฐ๋ฅผ ์ํํ๋ ๊ฒ ์ธ์๋, Realm Swift SDK๋ ์ฐ๊ธฐ ํธ๋์ญ์ (write transaction)์ ๋ช ์์ ์ผ๋ก ์ํํ์ง ์๊ณ ๋ ๋น ๋ฅธ ์ฐ๊ธฐ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ ํธ๋ฆฌํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
@ObservedRealmObject
๋๋ @ObservedResults
์์ฑ ๋ํผ(wrapper)๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฐ๊ธฐ ํธ๋์ญ์
(write transaction)์ ์์์ ์ผ๋ก ์ด ์ ์์ต๋๋ค. ์ํ ๊ฐ์ฒด์ ๋ํ ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ์ ์์ฑํ๋ ค๋ฉด $
์ฐ์ฐ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ Realm ๊ฐ์ฒด๋ ์ปฌ๋ ์
์ ๋ณ๊ฒฝํ๋ฉด ์์์ ์ฐ๊ธฐ๊ฐ ์์๋ฉ๋๋ค.
Realm SwiftUI ์์ฑ ๋ํผ(wrapper)๋ ๊ณ ์ ๋ ๋ฐ์ดํฐ์ ํจ๊ป ์๋ํ์ฌ ์ค๋ ๋ ์์ ์ฑ์ ์ ๊ณตํฉ๋๋ค. $
์(๋ฅผ) ์ฌ์ฉํ์ฌ ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ์ ๋ง๋ค๋ฉด Realm Swift SDK๊ฐ ๋๊ฒฐ๋ ๊ฐ์ฒด๋ฅผ ๋๊ฒฐ ํด์ ํ์ฌ ํด๋น ๊ฐ์ฒด์ ์ธ ์ ์๋๋ก ๊ด๋ฆฌํฉ๋๋ค.
๊ฐ์ฒด์ ์์ฑ ์ ๋ฐ์ดํธ
์ด ์์์์๋ ์ํ ๊ฐ์ฒด์ ์์ฑ ์ค ํ๋๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ์ ์์ฑํฉ๋๋ค. $dog.favoriteToy
์(๋) ๋ชจ๋ธ ๊ฐ ๊ฐ์ฒด์ favoriteToy
์์ฑ์ ๋ํ ๋ฐ์ธ๋ฉ์ ์์ฑํฉ๋๋ค.
์ด ์์ ์์ ์ฑ ์ฌ์ฉ์๊ฐ ํด๋น ํ๋๋ฅผ ์ ๋ฐ์ดํธํ๋ฉด Realm์ ์์์ ์ฐ๊ธฐ ํธ๋์ญ์ (write transaction)์ ์ด๊ณ ์ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํฉ๋๋ค.
struct EditDogDetails: View { var dog: Dog var body: some View { VStack { Text(dog.name) .font(.title2) TextField("Favorite toy", text: $dog.favoriteToy) } } }
๊ด์ฐฐ ๊ฒฐ๊ณผ ์ปฌ๋ ์ ์์ ๊ฐ์ฒด ์ถ๊ฐ ๋๋ ์ ๊ฑฐํ๊ธฐ
์ผ๋ฐ Realm ๊ฒฐ๊ณผ ์ปฌ๋ ์ ์ ๋ณ๊ฒฝํ ์ ์์ง๋ง ObservedResults ๋ ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ์ ์ฌ์ฉํ์ฌ ์ฐ๊ธฐ๋ฅผ ์ํํ ์ ์๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ปฌ๋ ์ ์ ๋๋ค. ๋ฐ์ธ๋ฉ๋ ์ปฌ๋ ์ ์ ์ ๋ฐ์ดํธ ํ๋ฉด Realm ์ ์์์ ์ฐ๊ธฐ ํธ๋์ญ์ (write transaction) (write transaction)์ ์ด๊ณ ๋ณ๊ฒฝ ์ฌํญ์ ์ปฌ๋ ์ ์ ์ ์ฅํฉ๋๋ค.
์ด ์์์์๋ onDelete
์์ $dogs.remove
์(๋ฅผ) ์ฌ์ฉํ์ฌ ๊ฒฐ๊ณผ ์ธํธ์์ ์์๋ฅผ ์ ๊ฑฐํฉ๋๋ค. ์ฌ๊ธฐ์ $dogs
์(๋ฅผ) ์ฌ์ฉํ๋ฉด BoundCollection
์ ๋ํ ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ์ด ์์ฑ๋์ด @ObservedResults
dogs
์ปฌ๋ ์
์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
addDogButton
์ $dogs.append
์(๋ฅผ) ์ฌ์ฉํ์ฌ ๊ฒฐ๊ณผ์ ํญ๋ชฉ์ ์ถ๊ฐํฉ๋๋ค.
์ด๋ฌํ ์กฐ์น๋ @ObservedResults
์ปฌ๋ ์
์ ์ง์ ๊ธฐ๋ก๋ฉ๋๋ค.
struct DogsListView: View { Dog.self) var dogs ( var body: some View { NavigationView { VStack { // The list shows the dogs in the realm. List { ForEach(dogs) { dog in DogRow(dog: dog) // Because `$dogs` here accesses an ObservedResults // collection, we can remove the specific dog from the collection. // Regular Realm Results are immutable, but you can write directly // to an `@ObservedResults` collection. }.onDelete(perform: $dogs.remove) }.listStyle(GroupedListStyle()) .navigationBarTitle("Dogs", displayMode: .large) .navigationBarBackButtonHidden(true) // Action bar at bottom contains Add button. HStack { Spacer() Button(action: { // The bound collection automatically // handles write transactions, so we can // append directly to it. This example assumes // we have some values to populate the Dog object. $dogs.append(Dog(value: ["name":"Bandido"])) }) { Image(systemName: "plus") } .accessibilityIdentifier("addDogButton") }.padding() } } } }
์ฐธ๊ณ
@ObservedResults
์์ฑ ๋ํผ(wrapper)๋ SwiftUI ๋ณด๊ธฐ์์ ์ฌ์ฉํ๊ธฐ ์ํ ๊ฒ์
๋๋ค. View ๋ชจ๋ธ์์ ๊ฒฐ๊ณผ๋ฅผ ๊ด์ฐฐํ๋ ค๋ฉด ๋ณ๊ฒฝ ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํ์ญ์์ค.
๋ชฉ๋ก์ ๊ฐ์ฒด ์ถ๊ฐํ๊ธฐ
๋ชฉ๋ก ์์ฑ์ด ์๋ @ObservedRealmObject
์(๊ณผ) ์๋ฐฉํฅ ๋ฐ์ธ๋ฉ์ด ์๋ ๊ฒฝ์ฐ ๋ชฉ๋ก์ ์ ๊ฐ์ฒด๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
์ด ์์์์ Person
๊ฐ์ฒด์๋ ํ ๋ง๋ฆฌ ์ด์์ ๊ฐ์ ๋๋ค ๊ด๊ณ๋ฅผ ํ์ฑํ๋ ๋ชฉ๋ก ์์ฑ์ด ์์ต๋๋ค.
class Person: Object, ObjectKeyIdentifiable { true) var _id: ObjectId (primaryKey: var firstName = "" var lastName = "" ... var dogs: List<Dog> }
์ฌ์ฉ์๊ฐ Save
๋ฒํผ์ ๋๋ฅด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ฉ๋๋ค.
์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ์ธ๋ถ ์ ๋ณด๋ก
Dog
๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค.Dog
๊ฐ์ฒด๋ฅผPerson
๊ฐ์ฒด์dogs
๋ชฉ๋ก์ ์ถ๊ฐํฉ๋๋ค
struct AddDogToPersonView: View { var person: Person var isInAddDogView: Bool var name = "" var breed = "" var weight = 0 var favoriteToy = "" var profileImageUrl: URL? var body: some View { Form { TextField("Dog's name", text: $name) TextField("Dog's breed", text: $breed) TextField("Dog's weight", value: $weight, format: .number) TextField("Dog's favorite toy", text: $favoriteToy) TextField("Image link", value: $profileImageUrl, format: .url) .keyboardType(.URL) .textInputAutocapitalization(.never) .disableAutocorrection(true) Section { Button(action: { let dog = createDog(name: name, breed: breed, weight: weight, favoriteToy: favoriteToy, profileImageUrl: profileImageUrl) $person.dogs.append(dog) isInAddDogView.toggle() }) { Text("Save") } Button(action: { isInAddDogView.toggle() }) { Text("Cancel") } } } } }
์์ฑํ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ Realm ๊ฐ์ฒด๋ฅผ Realm์ ๋ณต์ฌํ๊ธฐ
์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ทธ ์์ฑ ์ค ํ๋๋ฅผ ์์ญ์ ์ด๋ฏธ ์กด์ฌํ๋ ๊ฐ์ฒด๋ก ์ค์ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ ๊ฐ์ฒด๋ฅผ ์์ญ์ ์ถ๊ฐํ๋ ค๊ณ ํ๋ฉด ๋ค์๊ณผ ์ ์ฌํ ์ค๋ฅ๊ฐ ํ์๋ฉ๋๋ค.
Object is already managed by another Realm. Use create instead to copy it into this Realm.
์ด ๊ฒฝ์ฐ .create ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ์ด๊ธฐํํ๊ณ modified: .update
๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ์์ฑ์ ๊ธฐ์กด ๊ฐ์ฒด๋ก ์ค์ ํฉ๋๋ค.
์์
favoriteToy
์์ฑ์ด ๋จ์ํ String
์ด(๊ฐ) ์๋๋ผ ์ ํ์ DogToy
๊ฐ์ฒด์ธ DoggoDB Dog
๋ชจ๋ธ ๋ฒ์ ์ ์๊ฐํด ๋ณด์ธ์.
class Dog: Object, ObjectKeyIdentifiable { true) var _id: UUID (primaryKey: var name = "" ... var favoriteToy: DogToy? ... }
์ฑ์ด ์ Dog
๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ค๊ณ ํ ๋ DogToy
๊ฐ์ฒด๊ฐ ์ด๋ฏธ ์์ญ์ ์กด์ฌํ๋์ง ํ์ธํ ๋ค์ favoriteToy
์์ฑ์ ๊ธฐ์กด ๊ฐ์์ง ์ฅ๋๊ฐ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค.
์ Dog
Person
๊ฐ์ฒด์ ์ถ๊ฐํ๋ ค๊ณ ํ๋ฉด ๋ค์๊ณผ ์ ์ฌํ ์ค๋ฅ๊ฐ ๋ํ๋ ์ ์์ต๋๋ค.
Object is already managed by another Realm. Use create instead to copy it into this Realm.
Dog
๊ฐ์ฒด๋ Person
๊ฐ์ฒด์ dogs
์์ฑ์ ์ถ๊ฐ๋ ๋๊น์ง ๊ด๋ฆฌ๋์ง ์๋ ์ํ๋ก ์ ์ง๋ฉ๋๋ค. Realm Swift SDK๊ฐ Dog
๊ฐ์ฒด๋ฅผ ํ์ธํ์ฌ ํ์ฌ ๊ด๋ฆฌ ์ค์ธ ์์ญ์ ์ฐพ์๋ ์๋ฌด๊ฒ๋ ๋ฐ๊ฒฌํ์ง ๋ชปํฉ๋๋ค.
$
ํ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ Dog
๊ฐ์ฒด๋ฅผ Person
๊ฐ์ฒด์ ์ถ๊ฐํ๋ ๋น ๋ฅธ ์ฐ๊ธฐ๋ฅผ ์ํํ ๋ ์ด ์ฐ๊ธฐ๋ ๋ณด๊ธฐ์์ ์ก์ธ์คํ ์ ์๋ ์์ญ์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ @ObservedRealmObject
๋๋ @ObservedResults
์์ฑ ๋ํผ(wrapper)์ ์ํด ์์์ ์ผ๋ก ์ด๋ฆฌ๋ ์์ญ ์ธ์คํด์ค์
๋๋ค. ๊ทธ๋ฌ๋ ๊ธฐ์กด DogToy
๊ฐ์ฒด๋ ๋ค๋ฅธ ์์ญ ์ธ์คํด์ค์์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
์ด ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด .create ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ Dog
๊ฐ์ฒด ๋ฅผ ์ด๊ธฐํํ๊ณ modified: .update
๋ฅผ ์ค์ ํ๋ค ํ์ฌ ํด๋น favoriteToy
๊ฐ์ ๊ธฐ์กด ๊ฐ์ฒด ๋ก ์ค์ ํฉ๋๋ค.
// When working with an `@ObservedRealmObject` `Person`, this is a frozen object. // Thaw the object and get its realm to perform the write to append the new dog. let thawedPersonRealm = frozenPerson.thaw()!.realm! try! thawedPersonRealm.write { // Use the .create method with `update: .modified` to copy the // existing object into the realm let dog = thawedPersonRealm.create(Dog.self, value: ["name": "Maui", "favoriteToy": wubba], update: .modified) person.dogs.append(dog) }
๋ช ์์ ์ฐ๊ธฐ ์ํ
๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋น ๋ฅธ ์ฐ๊ธฐ๋ฅผ ์ํํ๊ธฐ ์ํด ์์์ ์ธ $
์(๋ฅผ) ์ฌ์ฉํ๋ ๋์ ๋ช
์์ ์ผ๋ก ์ฐ๊ธฐ ํธ๋์ญ์
(write transaction)์ ์ํํด์ผํ ์ ์์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ์ด ์์
์ ์ํํ ์ ์์ต๋๋ค.
์ฐ๊ธฐ๋ฅผ ์ํํ๋ ค๋ฉด ์ถ๊ฐ ๊ฐ์ฒด๋ฅผ ์กฐํํด์ผ ํฉ๋๋ค.
๋ณด๊ธฐ์์ ์ก์ธ์คํ ์ ์๋ ๊ฐ์ฒด์ ์ฐ๊ธฐ๋ฅผ ์ํํด์ผ ํฉ๋๋ค.
@ObservedRealmObject
๋๋ @ObservedResults
(์ผ)๋ก ๊ด์ฐฐ ์ค์ธ ๊ฐ์ฒด๋ฅผ ๊ฐ์ฒด๋ฅผ ์์ ํ๋ ๋ช
์์ ์ฐ๊ธฐ ํธ๋์ญ์
(write transaction)์ ์ํํ๋ ํจ์์ ์ ๋ฌํ๋ ๊ฒฝ์ฐ ๋จผ์ ํด๋น ๊ฐ์ฒด๋ฅผ ๊ณ ์ ํด์ ํด์ผ ํฉ๋๋ค.
let thawedCompany = company.thaw()!
๊ฐ์ฒด ๋๋ ์ปฌ๋ ์
์์ .realm
์(๋ฅผ) ํธ์ถํ์ฌ ์์ญ ๊ฐ์ฒด๋ฅผ ๊ด๋ฆฌํ๋ ์์ญ์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
let realm = company.realm!.thaw()
SwiftUI ์์ฑ ๋ํผ(wrapper)๋ ๊ณ ์ ๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์์ญ ๊ฐ์ฒด์ ์ฐ๊ธฐ ์ ์ ์์ญ์ ์ฌ๊ฐํด์ผ ํฉ๋๋ค.
์์
Company
๊ฐ์ฒด์ Employee
๊ฐ์ฒด ๋ชฉ๋ก์ด ์๋ DoggoDB ์ฑ ๋ฒ์ ์ ์๊ฐํด ๋ณด์ธ์. ๊ฐ Employee
์๋ Dog
๊ฐ์ฒด ๋ชฉ๋ก์ด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋น์ฆ๋์ค์์ ์ด์ ๋ก Employee
์ ์ฐ๊ฒฐ๋์ง ์๊ณ Company
๊ฐ์ฒด์์ ์ง์ ์ฌ์ฉํ ์ ์๋ Dog
๊ฐ์ฒด ๋ชฉ๋ก์ด ํ์ํ ์๋ ์์ต๋๋ค. ๋ชจ๋ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
class Company: Object, ObjectKeyIdentifiable { true) var _id: ObjectId (primaryKey: var companyName = "" var employees: List<Employee> var dogs: List<Dog> }
Company
๊ฐ์ฒด์ ์ก์ธ์คํ ์ ์์ง๋ง ๊ธฐ์กด ๊ฐ๋ฅผ ๊ธฐ์กด ์ง์์ ์ถ๊ฐํ๊ธฐ ์ํด ๋ช
์์ ์ฐ๊ธฐ๋ฅผ ์ํํ๋ ค๋ ๋ณด๊ธฐ๋ฅผ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ํจ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
// The `frozenCompany` here represents an `@ObservedRealmObject var company: Company` performAnExplicitWrite(company: frozenCompany, employeeName: "Dachary", dogName: "Maui") func performAnExplicitWrite(company: Company, employeeName: String, dogName: String) { // Get the realm that is managing the `Company` object you passed in. // Thaw the realm so you can write to it. let realm = company.realm!.thaw() // Thawing the `Company` object that you passed in also thaws the objects in its List properties. // This lets you append the `Dog` to the `Employee` without individually thawing both of them. let thawedCompany = company.thaw()! let thisEmployee = thawedCompany.employees.where { $0.name == employeeName }.first! let thisDog = thawedCompany.dogs.where { $0.name == dogName }.first! try! realm.write { thisEmployee.dogs.append(thisDog) } }