Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
29 | 30 | 31 |
Tags
- MVVM
- tableView
- map
- 애니메이션
- 리펙터링
- UITextView
- clean architecture
- 클린 코드
- swift documentation
- Refactoring
- collectionview
- 리팩토링
- UICollectionView
- Protocol
- uitableview
- Xcode
- swiftUI
- ios
- combine
- Clean Code
- uiscrollview
- SWIFT
- RxCocoa
- ribs
- rxswift
- HIG
- Human interface guide
- Observable
- 리펙토링
- 스위프트
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] SwiftUI의 Binding 이해하기, @Binding 구현 방법 (#protocol에서 get만 제공하는 프로퍼티에 set 기능 부여하기) 본문
iOS 응용 (swift)
[iOS - swift] SwiftUI의 Binding 이해하기, @Binding 구현 방법 (#protocol에서 get만 제공하는 프로퍼티에 set 기능 부여하기)
jake-kim 2023. 7. 31. 01:29SwiftUI의 Binding
- 바인딩이란 A가 변경될 때 같이 B도 변경해주어야하는 경우, A와 B를 바인딩 해놓으면 A가 변경되었을때 B는 자동으로 변경되게끔 하는 기법을 의미
- SwiftUI에서의 바인딩은 property wrapper 형태로 존재
- 구체적인 @Binding 개념은 이전 포스팅 글 참고
- Binding 인터페이스
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen @propertyWrapper @dynamicMemberLookup public struct Binding<Value> {
public var transaction: Transaction
public init(get: @escaping () -> Value, set: @escaping (Value) -> Void)
public init(get: @escaping () -> Value, set: @escaping (Value, Transaction) -> Void)
public static func constant(_ value: Value) -> Binding<Value>
public var wrappedValue: Value { get nonmutating set }
public var projectedValue: Binding<Value> { get }
public init(projectedValue: Binding<Value>)
public subscript<Subject>(dynamicMember keyPath: WritableKeyPath<Value, Subject>) -> Binding<Subject> { get }
}
- 핵심적인 요소만 보면 생성자에 get과 set 클로저를 받는 형태이고, get이 발생하면 내부적으로 가지고 있는 value를 리턴해주고, set이 발생하면 내부적으로 가지고 있는 value의 값을 변경하는 형태임을 추측이 가능
@propertyWrapper
struct Binding<Value> {
public init(get: @escaping () -> Value, set: @escaping (Value) -> Void)
}
직접 Binding 구현해보기
- SwiftUI의 @Binding을 똑같이 만들다기보단, Binding 동작을 이해하는 것이 목적이므로 가장 간단하게 Binding을 구현
- 예상한대로 get, set 클로저만 기록하고 있고 이 프로퍼티의 값은 외부 property의 값에 따라 자동으로 반영되도록 바인딩하는 역할
@propertyWrapper
struct MyBinding<T> {
private var get: () -> T
private var set: (T) -> Void
var wrappedValue: T {
get { get() }
nonmutating set { set(newValue) }
}
init(get: @escaping () -> T, set: @escaping (T) -> Void) {
self.get = get
self.set = set
}
}
ex) _age의 값을 변경하면 자동으로 ageBinding.wrappedValue의 값도 변경되도록하는 코드
var _age = 0
var ageBinding: MyBinding<Int> = {
MyBinding(get: {
_age
}, set: {
_age = $0
})
}()
print(ageBinding.wrappedValue)
_age = 2
print(ageBinding.wrappedValue)
/*
0
2
*/
Binding을 이용하여 protocol의 get만 제공하는곳에 set 추가하기
- 아래와 같은 protocol이 있을 때 age를 수정할 수 없는점이 존재
protocol Peronable {
var age: Int { get }
}
var person: Peronable
- property에 set을 추가하여 setter 기능을 만드는 것이 일반적이지만, Peronable은 공통으로 여러곳에서 사용하고 있었고 setter를 추가하면 다른 곳에 사이드 이펙을 줄 때 다른 방법이 필요
- 위에서 알아본 MyBinding을 사용하면 set 키워드 없이 사용이 가능
- Person 모델에 @MyBinding 키워드 사용
struct Person: Peronable {
@MyBinding var age: Int
}
- person은 Peronable 타입이지만 아래처럼 _age 프로퍼티를 만들고 이 값을 바인딩하면 setter 키워드 추가 없이, _age가 변경되면 자동으로 person 값에 setter가 가능
var _age = 0
var ageBinding: MyBinding<Int> = {
MyBinding(get: {
_age
}, set: {
_age = $0
})
}()
var person: Peronable = {
Person(age: ageBinding)
}()
결과)
print(ageBinding.wrappedValue)
_age = 2 // setter가 가능
print(ageBinding.wrappedValue)
/*
0
2
*/
* 전체 코드: https://github.com/JK0369/ExBinding
* 참고
'iOS 응용 (swift)' 카테고리의 다른 글
Comments