일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Firebase Analytics
- observable
- GCD
- 카카오뱅크 ios
- swift 5.9
- Firebase
- realm
- ios database
- swift database
- Combine
- swift 6
- arc
- Swift Tuist
- ios swiftdata
- Tuist Swift
- Subscribe
- swiftdata
- RxSwift
- SeSAC
- swift db
- KeyPath
- JSON
- Subject
- Tuist
- ribs
- xcode
- ios
- swift
- 네트워크 통신
- SwiftUI
- Today
- Total
천원의 개발
iOS KeyPath 정리 본문
안녕하세요. 천원입니다.
최근 TCA로 사이드 프로젝트를 진행하고 있는데 아래와 같이 \. 이런 문법이 종종 등장을 해서 정리하고자 이 글을 작성합니다.
AuthTextField(text: viewStore.binding(get: \.codeText, send: InViteCodeFeature.Action.textEditing), placeholder: "초대코드", error: viewStore.validCode) // TCA Binding
@Dependency(\.apiService) var apiServiced // Custom Dependency
먼저 Object-C에서 등장한 Key의 개념을 살펴보면
- Key는 문자열을 의미하고 Key값을 통해서 인스턴스의 프로퍼티에 접근하게 해주는 Objective-C에서 나온 개념이라고 합니다.
KVC(Key Value Coding)
- 인스턴스의 프로퍼티에 접근할 때 Key의 문자열로 접근하는 방식
- KVC는 Objective-C 런타임에 의존하므로 프로퍼티 앞에 @objc 붙여서 사용
- Objective-C의 것이기 때문에 NSObject가 가지고 있으므로 NSObject의 서브클래스여야 가능
class Person: NSObject {
@objc var name: String = "윤제"
}
let person = Person()
person.value(forKey: "name") // Optional(윤제)
person.setValue("천원", forKey: "name")
person.value(forKey: "name")
코드를 확인해 보면 dot syntax로 프로퍼티에 접근하는게 아니라 "name"이라는 문자열을 key값으로 name 프로퍼티에 접근을 한 모습입니다.
KVO(Key Value Observing)
- KVC와 동일하게 키값으로 프로퍼티에 접근하는데 Observing이 가능하다
- @objc dynamic 을 붙여서 사용
class Person2: NSObject {
@objc dynamic var name: String = "윤제"
}
person2.observe(\.name, options: [.old, .new]) { instance, change in
print(change.oldValue, change.newValue)
}
person2.name = "천원" //(윤제, 천원)
observe 매서드를 통해서 name의 변화를 관찰하고 변동 시에 작성해둔 print문이 실행되는 모습입니다. willSet 혹은 didSet과 유사한 역할을 수행할 수 있어 보입니다. observe 함수의 매개변수의 타입을 확인해 보면
KeyPath를 타입으로 \.name을 받는것을 알 수 있습니다. 이제 KeyPath는 무엇인지 확인해 보겠습니다.
KeyPath
- Key 값으로 프로퍼티에 접근이 가능한 것 처럼 KeyPath를 통해서도 접근이 가능하다
- KeyPath는 Root라는 타입(=Person타입)으로부터 구체적인 Value Type(프로퍼티타입)으로의 key의 경로를 의미
조금 더 설명을 보태자면 Person이라는 타입의 프로퍼티인 name 까지의 경로를 의미하는게 KeyPath라고 합니다. 코드로 확인해 보면
class Person {
var name: String = "윤제"
}
let person = Person()
person[keyPath: \Person.name] // 윤제
person[keyPath: \.name] // Root 타입은 생략 가능
Person -> name 의 KeyPath를 통해서 name 프로퍼티에 접근한 모습입니다. 그런데 우리가 앞서 궁금증을 가졌던 \. 형태는 이렇게 Dictionary 같은 형태가 아니라 매개변수로 \.을 받아서 사용을 했잖아요? 아래처럼!
AuthTextField(text: viewStore.binding(get: \.codeText, send: InViteCodeFeature.Action.textEditing), placeholder: "초대코드", error: viewStore.validCode) // TCA Binding
@Dependency(\.apiService) var apiServiced // Custom Dependency
이제 KeyPath를 활용한 함수를 작성해 봅시다.
KeyPath 활용
struct PersonInfo {
var name: String
var age: Int
}
struct School {
var kim: PersonInfo
var han: PersonInfo
func getKim() -> PersonInfo {
return self.kim
}
func getHan() -> PersonInfo {
return self.han
}
}
let kim = PersonInfo(name: "김감자", age: 12)
let han = PersonInfo(name: "한고구마", age: 13)
let school = School(kim: kim, han: han)
print(school.getKim()) // PersonInfo(name: "김감자", age: 12)
print(school.getHan()) // PersonInfo(name: "한고구마", age: 13)
School 구조체 내부에 각각에 프로퍼티를 return 하는 매서드가 존재하여 getKim, getHan을 통해서 프로퍼티를 가져온 모습이지만.. 학생의 수가 많아지면 그만큼 매서드의 수도 많아져야겠죠 이를 개선하기 위해서 우리는 KeyPath를 활용해 보겠습니다.
extension School {
func getChild(keyPath: KeyPath<Self, PersonInfo>) -> PersonInfo {
self[keyPath: keyPath]
}
}
print(school.getChild(keyPath: \.kim)) // PersonInfo(name: "김감자", age: 12)
print(school.getChild(keyPath: \.han)) // PersonInfo(name: "한고구마", age: 13)
getChild 라는 매서드의 파라미터로 KeyPath를 받아 사용한 모습입니다. 각각의 매서드를 사용하는 것 보다 재사용성이 올라간 모습이네요!
여기까지 KeyPath 정리였습니다.
출처:
https://developer.apple.com/documentation/swift/keypath
https://ios-development.tistory.com/982
'iOS&Swift🍎 > iOS' 카테고리의 다른 글
iOS SwiftData CRUD를 구현해보자 (0) | 2024.08.22 |
---|---|
iOS Background Tasks(백그라운드에서 API 호출하기) (0) | 2024.02.20 |
iOS Continuation 정리 (0) | 2023.11.24 |
iOS Tuist 적용하여 여러 프로젝트 관리하기 (0) | 2023.10.24 |
iOS Preview 보면서 codebase로 작업하기 (0) | 2023.07.12 |