๋ต๋ณ ์์ฝ
// Key Path
let person = Person(name: "Alice", age: 25)
let nameKeyPath = \Person.name // Person ๊ฐ์ฒด์ `name` ํ๋กํผํฐ์ ๋ํ Key Path
let ageKeyPath = \Person.age // Person ๊ฐ์ฒด์ `age` ํ๋กํผํฐ์ ๋ํ Key Path
์์๋ ๋ณ์์ ํจ์๋ฅผ ์ฐธ์กฐ๋ก ํ ๋นํ ์ ์๋ ๊ฒ์ฒ๋ผ ํ๋กํผํฐ์ ์์น๋ ์ฐธ์กฐ๋ก ํ ๋นํ ์ ์์ต๋๋ค. ํ๋กํผํฐ์ ์ง์ ์ ๊ทผํด์ ๊ฐ์ ๊บผ๋ด์ค๋๊ฒ ์๋๋ผ ํคํจ์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ ์ ์ผ๋ก ์ ๊ทผํ์ฌ ํน์ ํ์ ์ ์ด๋ค ํ๋กํผํฐ ๊ฐ์ ๊ฐ๋ฆฌ์ผ์ผ ํ ์ง ๋ฏธ๋ฆฌ ์ง์ ํด๋๊ณ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด๋ฅผ ๋ค๋ฅด๊ฒ ๋งํ๋ค๋ฉด ํคํจ์ค๋ ํ๋กํผํฐ์ ๋ํ ์ ๊ทผ์ ์ถ์ํํ ํ์ ์ ๋๋ค.
๋ถ๊ฐ ์ค๋ช
// MARK: - ํ๋กํ ์ฝ์ ํตํ ์ถ์ํ
// ํ๋กํ ์ฝ ์ ์
protocol Named {
var name: String { get }
}
// Person ํ์
์ด ํ๋กํ ์ฝ ๊ตฌํ
struct Person: Named {
var name: String
var age: Int
}
// Company ํ์
์ด ํ๋กํ ์ฝ ๊ตฌํ
struct Company: Named {
var name: String
var employees: Int
}
// ํ๋กํ ์ฝ์ ํตํ ์ถ์ํ
func printName(namedObject: Named) {
print("Name is: \(namedObject.name)")
}
// ๊ฐ์ฒด ์์ฑ
let person = Person(name: "Alice", age: 30)
let company = Company(name: "Swift Corp", employees: 100)
// ํ๋กํ ์ฝ ๊ธฐ๋ฐ ์ถ์ํ ์ฌ์ฉ
printName(namedObject: person) // ์ถ๋ ฅ: Name is: Alice
printName(namedObject: company) // ์ถ๋ ฅ: Name is: Swift Corp
// MARK: - ํคํจ์ค๋ฅผ ํตํ ์ถ์ํ
// Person ํ์
์ ์
struct Person {
var name: String
var age: Int
}
// Company ํ์
์ ์
struct Company {
var name: String
var employees: Int
}
// KeyPath๋ฅผ ํตํ ์ถ์ํ
func printName<T>(from object: T, keyPath: KeyPath<T, String>) {
let name = object[keyPath: keyPath]
print("Name is: \(name)")
}
// ๊ฐ์ฒด ์์ฑ
let person = Person(name: "Alice", age: 30)
let company = Company(name: "Swift Corp", employees: 100)
// KeyPath ์ฌ์ฉ
let personNameKeyPath = \Person.name
let companyNameKeyPath = \Company.name
printName(from: person, keyPath: personNameKeyPath) // ์ถ๋ ฅ: Name is: Alice
printName(from: company, keyPath: companyNameKeyPath) // ์ถ๋ ฅ: Name is: Swift Corp
KeyPath๊ฐ ํจ์ํ๋ ๋ฐ๋ ํ๋กํผํฐ๋ฅผ "์ถ์ํ"ํ๋ค๋ ๊ฒ์ด๋ค. ํ๋กํ ์ฝ์ ํตํ ์ถ์ํ๋ ์ธํฐํ์ด์ค ๊ฐ์ฒด๊ฐ ํ๋๋ ๋ง๋ค์ด์ ธ ๋ณต์ก์ฑ์ด ์ฆ๊ฐํ ๋ฟ๋ง ์๋๋ผ ์๋ก ๋ค๋ฅธ ํ์ ์ ๋ํด์ ์ถ์ํ๊ฐ ์ด๋ ต๋ค. keyPath๋ ํ๋กํผํฐ์ ๋ํด ๊ฐ์ฒด๋ฅผ ํ๋๋ ๋ง๋ค ํ์์์ด, ํ์ ์ด ์๋ก ๋ค๋ฅด๋๋ผ๋, ์ถ์ํ๋ฅผ ๊ฐ๋ฅ์ผ ํด์ค๋ค.
keyPath๋ ํ์ ์ ํตํด ์๋ณธ ๊ฐ์ฒด๋ฅผ ๊ฑด๋ค์ง ์๊ณ ๋ ์ฝ๊ธฐ/์ฐ๊ธฐ ์์ ์ ํ์ ๊ฑธ ์ ์๋ค. KeyPath<Root, Value>, PartialKeyPath<Root> ํ์ ์ผ๋ก ์ ์ธํ๋ฉด ํ๋กํผํฐ์ ๋ํ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํ ๊ฒฝ๋ก๋ฅผ ์ด์ด์ค๋ค.
WritableKeyPath<Type, Value>, ReferenceWritableKeyPath<Root, Value> ํ์ ์ผ๋ก ์ ์ธํ๋ฉด ์ฝ๊ธฐ/์ฐ๊ธฐ๊ฐ ๋ชจ๋ ๊ฐ๋ฅํ ๊ฒฝ๋ก๋ฅผ ์ด์ด์ค๋ค. ๊ฐํ์ ๊ณผ ์ฐธ์กฐํ์ ์ ํน์ฑ ํ์ ๊ฐ์ ๋ณํ๊ฐ ์๊ธฐ๋ฉด ์๋ก์ด ๊ฐ์ ๋ด๋๊ธฐ ๋๋ฌธ์ ๋ฐ๊พธ๋ ค๋ ๊ฐ์ฒด๋ฅผ var๋ก, ๋ฉ๋ชจ๋ฆฌ์ฃผ์๋ ๊ฐ๊ณ ์ฃผ์ ๋ด ๊ฐ๋ง ๋ฐ๊พธ๋ ReferenceWritableKeyPath๋ ๋ฐ๊พธ๋ ค๋ ๊ฐ์ฒด๋ฅผ let์ผ๋ก ์ ์ธํด์ฃผ์ด์ผํ๋ค.
๊ฐํ์ ๊ณผ ์ฐธ์กฐํ์ ์ ํน์ฑ ํ์ ๊ฐ์ ๋ณํ๊ฐ ์๊ธฐ๋ฉด ์๋ก์ด ๊ฐ์ ๋ด๋๊ธฐ ๋๋ฌธ์ ์ ๊ทผํ๋ ค๋ ๋ณธ์ฒด ๊ฐ์ฒด๊ฐ ๊ฐํ์ ์ด๋ฉด var๋ก, ์ ๊ทผํ๋ ค๋ ๋ณธ์ฒด๊ฐ ์ฐธ์กฐํ์ ๊ฐ์ฒด๋ผ๋ฉด let์ผ๋ก ์ ์ธํด์ฃผ์ด์ผํ๋ค.
struct Person {
var name: String
}
var person = Person(name: "Alice")
let writableNameKeyPath: WritableKeyPath<Person, String> = \Person.name
person[keyPath: writableNameKeyPath] = "Bob" // ์๋ก์ด ์ธ์คํด์ค๊ฐ ์์ฑ๋จ
class Person {
var name: String
}
let person = Person(name: "Alice")
let referenceWritableNameKeyPath: ReferenceWritableKeyPath<Person, String> = \Person.name
person[keyPath: referenceWritableNameKeyPath] = "Bob" // ๊ฐ์ ๊ฐ์ฒด๊ฐ ์์ ๋จ
ํคํจ์ค ์ฝ๊ธฐ/์ฐ๊ธฐ ๋ชจ๋ ๊ฐ๋ฅํ ํ์ ์๋ WritableKeyPath<Type, Value> ์ ReferenceWritableKeyPath<Root, Value> ๊ฐ ์๋ค. ์ ์๋ ๊ฐํ์ ์, ํ์๋ ์ฐธ์กฐํ์ ์ ์ ์ฉ๋๋ค. ๋ ๋ชจ๋ ํ๋กํผํฐ์ ๋ํ ๊ฒฝ๋ก๋ฅผ ์ฐธ์กฐํ๋ ํ์ ์ผ๋ก ์ฝ๊ธฐ/์ฐ๊ธฐ๋ฅผ ๋ชจ๋ ์ด์ด์ค๋ค๋ ํน์ง์ด ์๋ค.
struct Person {
let name: String
let age: Int
}
let person = Person(name: "Alice", age: 30)
// PartialKeyPath ์ฌ์ฉ
let partialKeyPath: PartialKeyPath<Person> = \Person.name
// ์ฝ๊ธฐ ์ ์ฉ ์ ๊ทผ
let nameValue = person[keyPath: partialKeyPath] // "Alice"
print(nameValue) // ์ถ๋ ฅ: Alice
// MARK: - KeyPath
struct Person {
let name: String
let age: Int
}
let person = Person(name: "Alice", age: 30)
// ์ฝ๊ธฐ ์ ์ฉ KeyPath ์ฌ์ฉ
let nameKeyPath: KeyPath<Person, String> = \Person.name
let ageKeyPath: KeyPath<Person, Int> = \Person.age
print("์ด๋ฆ: \(person[keyPath: nameKeyPath])") // ์ถ๋ ฅ: ์ด๋ฆ: Alice
print("๋์ด: \(person[keyPath: ageKeyPath])") // ์ถ๋ ฅ: ๋์ด: 30
๋ค์์ผ๋ก ์ ๊ทผํ๋ ค๋ ๊ฐ์ฒด์ ๋ํด read only ๋ก ์ ํํ๋ keyPath๋ KeyPath<Root, Value>, PartialKeyPath<Root> ํ์ ์ด ์๋ค. ๋ ํ์ ๋ ๊ฐ์ฒด์ ๋ํด read only ์ ํ์ ๊ฑธ์ด ๊ฒฝ๋ก๋ฅผ ์ฐธ์กฐํด์ฃผ๋ฉฐ ์ ์๋ ๊ฐํ์ ์ ๋ํ ๊ฒฝ๋ก, ํ์๋ ์ฐธ์กฐํ์ ์ ๋ํ ๊ฒฝ๋ก์ด๋ค. ์ด๋ PartialKeyPath๋ readOnly์ ์ฐธ์กฐํ์ ์ด๋ผ๋ ํน์ฑ ๋๋ถ์ ํ๊ฐ์ง ๋๋ค๋ฅธ ํน์ง์ด ์๊ธฐ๋๋ฐ ๋ฐ๋ก type-erase๊ฐ ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ด๋ค.
์๋ก๋ค๋ฅธ ํ์ ์์๋ PartialKeyPath<Root> ๋ฅผ ์ด์ฉํ๋ค๋ฉด ํ๋กํผํฐ์ ๋ํ ์ถ์ํ๊ฐ type์ ์๊ด์์ด ์ด๋ฃจ์ด์ง๋ฉด์ ๊ฐ์ ํด๋์ค ๋ด์์ ์๋ก๋ค๋ฅธ ํ์ ์ ํ๋กํผํฐ์ ๋ํ ์ถ์ํ๋ฅผ ํ๋์ ํ์ ์ผ๋ก ํ ์ ์๊ฒ ํด์ค๋ค.
struct Person {
var name: String
var age: Int
}
// AnyKeyPath ์ปฌ๋ ์
์์ฑ
let keyPaths: [AnyKeyPath] = [\Person.name, \Person.age]
let person = Person(name: "Alice", age: 30)
// AnyKeyPath๋ฅผ ์ฌ์ฉํ์ฌ ํ๋กํผํฐ ์ ๊ทผ
for keyPath in keyPaths {
if let nameKeyPath = keyPath as? KeyPath<Person, String> {
print("Name: \(person[keyPath: nameKeyPath])") // ์ถ๋ ฅ: Name: Alice
} else if let ageKeyPath = keyPath as? KeyPath<Person, Int> {
print("Age: \(person[keyPath: ageKeyPath])") // ์ถ๋ ฅ: Age: 30
}
}
๋ง์ฝ keyPath ์ ๊ตฌ์ฒดํ์ ์ type-erased ํ๊ณ ์ถ๋ค๋ฉด AnyKeyPath๋ก ์ ์ธํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ๋ค๋ง ์ฝ๊ธฐ/์ฐ๊ธฐ ์์ ์ด ๋ค์ด๊ฐ ๋๋ ๋ฐ๋์ ๊ตฌ์ฒดํ์ ์ผ๋ก ๋ค์ด์บ์คํ ์ ํด์ฃผ์ด์ผํ๋ค.
keyPaths๋ Hashable ํ๋กํ ์ฝ์ ์ฑํํ๊ณ ์๋ค. ๋ฐ๋ผ์ ๋์ ๋๋ฆฌ์ ํค๊ฐ์ผ๋ก ํ์ฉํ ์ ์์๊ณผ ๋์์ ๊ธฐ์กด์ ํ๋์ ํ์ ์ด ํค๊ฐ์ผ๋ก ๋ค์ด๊ฐ์ผ๋ฉด keyPath๋ฅผ ํตํด ๋ค์ํ ์ ๋ณด๋ฅผ ํค๊ฐ์ผ๋ก ๋ฃ์ ์ ์๋ค๋ ๊ฒ์ด ์ฅ์ ์ด๋ค.
๋ค๋ง ํ๊ฐ์ง ๋จ์ ์ ํคํจ์ค๋ ๊ฐ์ ๋ณํ๋ฅผ ์ต์ ๋นํ ์ ์๋ค๋ ๊ฒ์ด๋ค. ๊ฐ์ ๋ณํ๋ฅผ ์ต์ ๋นํ๊ณ ์ถ๋ค๋ฉด ํ๋กํ ์ฝ์ด๋ ์ต์ ๋ฒ ํจํด์ ์ ์ฉํ KVO, ํด๋ก์ ์ฝ๋ฐฑ์ ์ ์ฉํ Property Wrapper๋ฅผ ์จ์ผํ๋ค.
๋ ํผ๋ฐ์ค
Introduction to Swift Keypaths: https://www.youtube.com/watch?v=z4lTKBS0ZbQ
'๐ฆ Flutter' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Target of URI doesn't exist: 'firebase_options.dart' ์๋ฌ (1) | 2024.07.24 |
---|---|
The plugin "cloud_firestore" requires a higher minimum iOS deployment version than your application is targeting. ์๋ฌ (1) | 2024.07.24 |
Swift ์์ Key-Value Observing ์ด๋? (0) | 2024.06.24 |
์์ ฏ์ Key ๋ฅผ ์ฌ์ฉํด์ผํ๋ ์ด์ (0) | 2024.06.12 |
| WWDC 16 | Concurrent Programming with GCD (0) | 2024.06.05 |