[swift] 키 경로

Youngwoo Lee·2021년 4월 7일
0

iOS

목록 보기
4/46
post-thumbnail

Swift는 함수가 일급시민으로서 상수나 변수에 참조를 할당할 수 있다

Swift의 함수, 클로저에 대해 공부해 본 사람이라면 누구나 이 문장을 본 적이 있을 겁니다!

func someFunction(paramA: Any, paramB: Any) {
	print("someFunction called...")
}

var functionReference = someFunction(paramA: paramB:)

functionReference("A", "B") //someFunction called...
functionReference = anotherFunction(paramA: paramB:)

그리고 이 예제를 보면서 공부하셨겠죠??ㅎ

며칠 전에 프로젝트를 진행하면서, "그럼 프로퍼티의 위치만 참조하는 방법은 없을까?"를 생각하게 되었는데.. 해당 프로퍼티의 타입이 값 타입이여서 어떻게 할 도리가 없었습니다...ㅠ

그러던 중! 키 경로에 대해서 알게 되었죠ㅎㅎ

그럼 한 번 공부하러 가보죠

키 경로

앞서 말했다 싶이 프로퍼티도 함수 처럼 값을 바로 꺼내오는 것이 아니라 어떤 프로퍼티의 위치만 참조하도록 할 수 있습니다. 바로 키 경로를 활용하는 것이지요

키 경로 타입은 AnyKeyPath라는 클래스로부터 파생됩니다

공식 문서를 보면 any 루트 타입으로 부터 값 타입에 이르는 type-erased key path..? 라고 되어 있다..?? 잘 모르겠네...ㅠㅠ

일단, 다른 자료를 찾아보면 이 타입은
WritableKeyPath<Root, Value>, ReferenceWritableKeyPath<Root, Value> 타입으로 제일 많이 확장된 키 경로 타입이라고 한다

해당 타입들은 제네릭 클래스로

이러한 기능을 가지고 있다

근데 이것만 보면, 정확히 어떤 느낌인지 안 다가 올 것이다

일단 키 경로의 구성을 보자!!

\타입이름.경로.경로.경로

아하! 타입이름과 프로퍼티 이름들로 타고 들어가는 것이구만?!

class Person {
	var name: String
    
   	init(name: String) {
   		self.name = name
   	}
}

struct Stuff {
	var name: String
   	var owner: Person
}

print(type(of: \Person.name)) // ReferenceWritableKeyPath<Person, String>
print(type(of: \Stuff.name)) // WritableKeyPath<Stuff, String>

또 다른 예제


class Person {
   let name: String
   init(name: String) {
       self.name = name
   }
}

struct Stuff {
   var name: String
   var owner: Person
}

let yagom = Person(name: "yagom")
let hana = Person(name: "hana")
let macbook = Stuff(name: "Macbook Pro", owner: yagom)
var iMac = Stuff(name: "iMac", owner: yagom)
let iPhone = Stuff(name: "iPhone", owner: hana)

let stuffNameKeyPath = \Stuff.name
let ownerkeyPath = \Stuff.owner
let ownerNameKeyPath = ownerkeyPath.appending(path: \.name)

print(macbook[keyPath: stuffNameKeyPath]) // Macbook pro
print(iMac[keyPath: stuffNameKeyPath]) // iMac

키 경로를 잘 활용하면 프로토콜과 마찬가지로 타입 간의 의존성을 낮추는데 많은 도움을 준다!!

또, 애플의 프레임워크는 키-값 코딩 등 많은 곳에서 키 경로를 활용하므로, 알아두면 정말 좋다!!

그리고 고차 함수에서도 활용하는 방법이 있다!!

struct Person {
    let name: String
    let nickname: String?
    let age: Int
    
    var isAdult: Bool {
        return age > 18
    }
}

let yagom: Person = Person(name: "yagom", nickname: "bear", age: 100)
let hana: Person = Person(name: "hana", nickname: "na", age: 100)
let happy: Person = Person(name: "happy", nickname: nil, age: 3)

let family: [Person] = [yagom, hana, happy]
let names: [String] = family.map( \.name ) // family.map{ $0.name }
print(names)

잘 사용한다면 정말 여러 방면에서 사용할 수 있을 것 같다!!!

기억 안날 때마다 보자!!!

profile
iOS Developer Student

0개의 댓글