Key-Value Coding(KVC)
- 객체의 값에 직접 접근하지 않고, 문자열 키나
KeyPath
를 사용하여 참조를 통해 간접적으로 접근하는 방법
- 직접 접근은 일반적으로 컴파일 타임에 static dispatch로 메서드나 프로퍼티의 위치를 결정함
- 간접 접근은 일반적으로 런타임에 dynamic dispatch로 메서드나 프로퍼티의 위치를 결정하지만,
KeyPath
의 경우 컴파일 타임에 타입 검사를 거치므로 dynamic dispatch가 일어나지 않음
struct Dog {
var name: String
}
let myDog = Dog(name: "Fido")
print(myDog.name) // 직접 접근
let nameKeyPath = \\Dog.name
print(myDog[keyPath: nameKeyPath]) // KeyPath를 통한 간접 접근
Key-Path Expression
- Key path 표현식은 타입의 프로퍼티나 서브스크립트를 참조함
- 주로 key-value observing(KVO)과 같은 동적 프로그래밍 작업에서 key path 표현식을 사용함
- Key path 표현식은 컴파일 타임에,
KeyPath
클래스의 인스턴스로 대체됨
struct SomeStructure {
var someValue: Int
}
let s = SomeStructure(someValue: 12)
let pathToProperty = \\SomeStructure.someValue
let value = s[keyPath: pathToProperty]
// value is 12
- 타입 추론이 가능한 상황에서는 타입을 생략할 수 있음
// Example of KVO
class SomeClass: NSObject {
@objc dynamic var someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
}
}
let c = SomeClass(someProperty: 10)
c.observe(\\.someProperty) { object, change in
// ...
}
path
는 self
를 참조함으로써 전체 인스턴스를 참조하는 identity key path를 생성할 수 있음
var compoundValue = (a: 1, b: 2)
// Equivalent to compoundValue = (a: 10, b: 20)
compoundValue[keyPath: \\.self] = (a: 10, b: 20)
- 일반적으로 함수나 클로저를 제공하는 상황에서, key path 표현식을 사용할 수 도 있음
struct Task {
var description: String
var completed: Bool
}
var toDoList = [
Task(description: "Practice ping-pong.", completed: false),
Task(description: "Buy a pirate costume.", completed: true),
Task(description: "Visit Boston in the Fall.", completed: false),
]
// Both approaches below are equivalent.
let descriptions = toDoList.filter(\\.completed).map(\\.description)
let descriptions2 = toDoList.filter { $0.completed }.map { $0.description }