맛동산이

Swift) KeyPath란 본문

앱/Swift

Swift) KeyPath란

진ddang 2024. 1. 1. 21:23
struct Person {
	var name: String
	var age: Int
}

let jinyong = Person(name: "jin", age: 28)
let jung = Person(name: "jung", age: 27)
let shana = Person(name: "shana", age: 25)

let people = [jinyong, jung, shana]
var name = people.map { $0.name }
// name = ["jin", "jung", "shana"]

이러한 코드가 있을때, 키패스를 사용하면 다음과 같이 동일하게 작동한다.

var name = people.map { $0.name }
var name = people.map(\.name)

키패스와 동일하게 작동하는것이 바로 KVC이다.

KVC(Key Value Coding)

  • key : Key는 문자열을 의미하며, 이 key값을 통해서 인스턴스의 프로퍼티에 간접적으로 접근할수 있도록 하는 objective-c 개념
class Person: NSObject {
	@objc var name: String?
}
let person = Person()
person.value(forKey: "name") //nil
person.setValue("jin", forKey: "name") // name = "jin"
person.value(forKey: "name") // "jin"

KeyPath로의 접근

위에서도 key값으로 프로퍼티에 접근했지만, keyPath를 통해서도 접근이 가능하다.

keyPath로의 접근은 , RootType부터 구체적인 property type으로의 key경로를 의미한다.

  • 즉 keyPath로 인스턴스 안 프로퍼티 접근이 가능하다.는 말이다.
person[keyPath: \.Person.name]
person[keyPath: \.name] //루트타입은 생략 가능(추론이 명확하게 가능하다면)

키패스 직접 정의

KeyPath<Root, Property>
//루트가 Root, 프로퍼티가 .뒤에오는 값이다. 즉
KeyPath<Person, name> 타입이 person[keyPath: \.Person.name]에서
\.Person.name 이라는것이다.

따라서 다음과 같은 함수 정의가 가능하다.

extension Person {
	func getName(keyPath: KeyPath<Self, name>) -> name {
		self[keyPath: keyPath]
	)
}
let jin = person(name: "jin")
jin.getName(keyPath: \.name) //"jin"
jin.getName(keyPath: \.age) // nil > 에러뜸

키패스를 사용하는 이유

  • KVC(Key Value Coding)에서는 프로퍼티에 접근할 때 문자열 key값을 이용했지만, KeyPath를 이용하면 문자열이 아닌 프로퍼티  이름으로 접근이 가능 -> runtime error 방지에 유리
  • 즉 String값의 오타를 줄일수 있다.

참고자료

bookmark

반응형