Swift에서 어느 속성에 접근할 때 직접적인 방법과 간접적인 접근 방식이 있다. 직접적인 방법으로는 우리가 흔히 사용하는 '.'을 통해 값에 직접 접근하는 방식이고 간접적인 방식은 KVC나 KeyPath를 통해 문자열 Key나 경로를 통해 간접적으로 접근하는 방식이다.
직접적인 접근 방식은 간단하고 명료하게 값에 접근할 수 있고, 간접적인 방식은 동적이고 유연하게 접근 가능하다.
KVC와 KeyPath 모두 객체의 속성에 간접적으로 접근하는 메커니즘을 제공하지만, 기본 원리와 사용법에는 명확한 차이점이 있다. 각 개념에 대해 알아보도록 하자
KVC는 객체의 속성에 접근하기 위한 메커니즘으로 객체의 속성에 문자열 키를 사용하여 동적으로 접근하고 수정할 수 있다.
objective-C 에서 나온 개념으로, NSObject를 상속받은 클래스에서 사용된다. (KVC를 통해 접근 할 프로퍼티는 @objc, dynamic 키워드를 추가해야 함)
KVC는 컴파일 타임에서 타입 안정성을 제공하지 않는다. 오타나 잘못된 키를 사용하면 런타임에 오류가 발생한다.
setValue(_:forKey:)와 value(forKey:) 메서드를 사용하여 값을 설정하거나 가져올 수 있다.
키(Key): 객체의 속성을 나타내는 문자열.
ex) name, age 등
값(value): 해당 키에 할당된 실제 데이터 값.
ex) "고라니", 89 등
class Person: NSObject {
@objc dynamic var name: String = ""
@objc dynamic var age: Int = 0
}
let john = Person()
john.setValue("John", forKey: "name")
john.setValue(28, forKey: "age")
if let name = john.value(forKey: "name") as? String {
print(name) // 출력: John
}
기본적으로 우리가 많이 사용하는 방법인 객체의 프로퍼티에 직접 접근하는 방법은 명확하고 안전한 방법이지만 동적이지 않고 유연하지 않다. 그렇기 때문에 특수한 상황에서는 KVC방법이 유용할 수 있다.
그러면 KVC의 장담점에 대해 좀더 알아보자.
Swift 4부터는 KeyPath 타입이 도입되어 KVC를 더 안전하고 표현력 있게 사용할 수 있게 되었습니다. \ClassName.propertyName 형식으로 KeyPath를 생성할 수 있습니다.
KeyPath 는 KVC를 더 안전하게 사용할수 있다. \타입 이름.프로퍼티 이름 형식으로 KeyPath를 생성할 수 있다.
KeyPath는 객체의 속성에 대한 Type-Safty 참조를 제공한다.
Swift의 모든 데이터 타입에서 사용할 수 있다. (클래스, 구조체, 열거형)
KeyPath는 컴파일 시점에 타입 검사를 제공하여 잘못된 속성 참조는 컴파일 오류가 발생한다.
struct Student {
var name: String
}
let keyPathForName = \Student.name
let student = Student(name: "Alice")
let retrievedName = student[keyPath: keyPathForName]
KVC와 KeyPath는 각각 장점과 단점이 존재한다. 이 둘을 비교 해보겠다.
간접적인 접근: 둘 다 객체의 속성에 간접적으로 접근하는 메커니즘을 제공한다. 중간 매개체(문자열 또는 KeyPath 객체)를 사용하여 해당 속성에 접근
동적 접근: 실행 시점에 동적으로 특정 속성에 접근할 수 있다.
재사용성: 재사용성 향상 가능. 예) 특정 속성을 기준으로 정렬 or 필터링 등의 작업을 일반화하여 여러 타입에 대해 동일한 로직 적용 가능
Swift와의 통합 KVC는 objective-C로부터 사용되었던 것이지만 현재 Swift에서도 충분히 사용 가능, KeyPath는 Swift에서 도입된 기능이기 때문에 당연히 Swift의 다양한 데이터 타입과 잘 통합된다.
동적 접근: 속성 이름을 문자열로 사용하여 동적으로 속성에 접근할 수 있음
objective-C 호환: KVC는 objective-C와 Swift에서 모두 사용할 수 있다. objective-C와 혼용하여 작성된 프로젝트에서 유용
KVO(Key-Value-Observing) 통합: KVC는 KVO와 자연스럽게 통합 가능하다. 이를 통해 객체의 속성 변화를 관찰하는 것이 가능
타입 안정성 부족: 컴파일 시점에 타입 검사를 제공하지 않아 런타임에 오류가 발생할 수 있음.
런타임 오류: 잘못된 키나, 오타는 런타임 오류를 발생시킨다.
제한된 사용: Swif의 구조체나 열거형에서는 KVC를 직접 사용할 수 없음. NSObject를 상속받은 클래스에서만 사용 가능
타입 안전성: 컴파일 시점에서 타입 검사를 제공하여 잘못된 속성 참조는 컴파일 오류로 확인 가능
Swift 통합: Swift의 클래스, 구조체, 열거형에서 모두 사용 가능
재사용 및 일반화: 코드를 일반화하고 재사용 가능. 이를 통해 함수나 메서드의 일반적인 동작을 정의하는 데 유용하다.
명확한 문법: 명확한 문법을 가지고 있어, 코드의 의도가 잘 드러난다.
KVC와 KeyPath는 각각 고유한 장점과 사용 사례를 가지고 있다. 상황에 따라 적절한 방법을 선택하는 것이 중요하다.
KVC는 동적인 접근이 필요할 때나 objective-C와 호환성이 중요하거나 KVO구현이 필요할 때 유용하며, KeyPath는 좀더 안전하고 Swift 타입을 유연하게 활용할 때 유용하게 사용 될 수 있다.
사실 아직까지는 KVC와 KeyPath의 적절한 사용사례를 직접적으로 경험해보지 못해서 얼마나 유용한지는 체감하지 못하지만 유용하게 사용할 수 있는 상황이 오면 적절하게 사용해보도록 하겠다.