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 |
Tags
- uitableview
- 리펙토링
- Human interface guide
- 스위프트
- swiftUI
- RxCocoa
- SWIFT
- MVVM
- 리팩토링
- uiscrollview
- tableView
- 클린 코드
- HIG
- map
- clean architecture
- UITextView
- ribs
- rxswift
- UICollectionView
- 리펙터링
- combine
- Xcode
- Protocol
- Clean Code
- 애니메이션
- Refactoring
- ios
- Observable
- collectionview
- swift documentation
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - SwiftUI] State, Binding 개념, 사용 방법 본문
State 란?
- SwiftUI에 의해 관리되는 property wrapper 타입
struct ContentView: View {
@State var age = 20 // <-
var body: some View {
Text("Hello, world!")
.padding()
}
}
- 내부 코드
- projectedValue에 나오는 Binding 개념은 아래에서 계속
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen @propertyWrapper public struct State<Value> : DynamicProperty {
public init(wrappedValue value: Value)
public init(initialValue value: Value)
public var wrappedValue: Value { get nonmutating set }
public var projectedValue: Binding<Value> { get }
}
- SwiftUI에 의해 관리된다는 것은?
- @State로 선언한 프로퍼티는 값이 변경되면 뷰 계층 구조의 부분을 업데이트
- @State를 자식 뷰에 전달하면 부모에서 값이 변경될 때마다 자식을 업데이트
- 단, 자식 뷰에서 값을 수정하려면, 부모에서 자식으로 Binidng을 전달하여 자식 뷰에서 값을 수정이 가능
ex) 자식 뷰가 @State로 관리되는 경우 - 자식 뷰에서 값을 변경해도 부모 뷰의 값은 바뀌지 않음
- 자식 뷰의 @State isPlaying 프로퍼티의 값이 변경된다 하더라도 부모 뷰의 isPlaying값은 바뀌지 않음
struct ContentView: View {
@State private var isPlaying = false
var body: some View {
PlayButton(isPlaying: isPlaying)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print("isPaying = \(isPlaying)") // 자식 뷰에서 버튼을 눌러도 부모 isPlaying값은 언제나 false
}
}
}
}
struct PlayButton: View {
@State var isPlaying: Bool
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
ex) Binding을 이용하여 자식 뷰에서 값이 변경되면 부모 뷰에도 값이 변경되도록 처리
자식 뷰에서 @State를 @Binidng으로 변경하고, 부모 뷰에서 자식 뷰로 넘겨줄때 Binding을 넘겨주는 방식
struct ContentView: View {
@State private var isPlaying = false
var body: some View {
PlayButton(isPlaying: $isPlaying) // <-
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print("isPaying = \(isPlaying)")
}
}
}
}
struct PlayButton: View {
@Binding var isPlaying: Bool // <-
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
State를 사용할때의 주의점
- @State 프로퍼티는 항상 private으로 선언하고 가장 상위 뷰에서 @State를 관리할 것
- 뷰를 초기화할때, @State 프로퍼티 값도 같이 초기화하게되면 SwiftUI에서 @State 프로퍼티를 관리하는 공간인 Storage에서 conflict가 나기 때문
- 만약 상위 뷰에서의 State값을 하위 뷰에서도 접근할 수 있게하려면 Binding을 하위 뷰에 넘겨주거나 상위 뷰에서 read-only property로 설정하여 값을 공유
Binding 이란?
- 신뢰적으로 값을 읽고 쓸수 있는 property wrapper 타입
- "바인딩"의 의미: 자식 뷰의 특정 property 값이 변경되면 부모의 특정 property 값도 변경 (+양방향)
- 위 State에서 알아본대로 바인딩을 통해 데이터를 표시하고 변경하는 뷰 간에 양방향 연결을 만드는 것
- 내부 코드
@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 }
}
ex) Binding property
- @Binding 으로 선언
struct PlayButton: View {
@Binding var isPlaying: Bool // <-
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
- State안의 projected value
struct ContentView: View {
@State private var isPlaying = false
var body: some View {
PlayButton(isPlaying: $isPlaying) // <-
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print("isPaying = \(isPlaying)")
}
}
}
}
* 전체 코드: https://github.com/JK0369/ExState-SwiftUI
* 참고
'iOS 기본 (SwiftUI)' 카테고리의 다른 글
Comments