SwiftUI | @State, @Binding, @ObservedObject

SwiftUI에서 상태를 제공하는 세 가지.
– State property
– Binding
– Observed Object


state property

https://developer.apple.com/documentation/swiftui/state

String, Int, Bool 과 같은 간단한 값을 저장하고 View의 현재 상태를 표시하기 위해 사용된다.
private 로 선언되어야 한다.

정의하는 법

@State private var userID: Int = 0

위와 같이 @state 를 붙여서 정의한다.


View 에서 state property 표시하기

@State private var message = “”

Text(message)

– 이 경우는 Textmessage의 값을 표시하는 단순한 참조입니다.
message property 값의 변화가 생겼을 때 SwiftUI는 새로 렌더링되어 새로운 값을 표시합니다.


사용자로부터 View에 입력된 값을 state property 에 넣기

@State private var message = “”

TextField(“메세지를 입력해주세요.”, text: $message)

$ 를 사용해서 state property 를 호출합니다.
– 사용자가 TextField 에 새로운 값을 입력시키면 message property에도 반영됩니다.
message 를 참조하고 있던 View 가 있다면 새로 렌더링되어 새로운 값이 표시됩니다.


Binding

https://developer.apple.com/documentation/swiftui/binding

A라는 부모뷰에서 a라는 하위뷰를 사용하고,
a는 A의 state property 를 표시하고 능동적으로 값이 변화해야할 때,
필요한 것이 Binding 입니다.



📺 예제

struct CurrentMessageTextView: View {
    @State private var message = "안녕하세요. SwiftUI는 어떠신가요"

    var body: some View {
        Text(message)
            .padding(.all, 10.0)
            .border(Color.green, width: 2.0)
    }
}

struct ContentView: View {
    var body: some View {
        VStack(spacing: 10.0) {
            CurrentMessageTextView()
            CurrentMessageTextView()
        }
    }
}

– 위의 코드를 살펴보면, CurrentMessageTextViewContentView 의 자식뷰로 구성되어 있습니다.
– ContentView 에 state property 를 추가하고 CurrentMessageTextView 들이 그 값을 참조하기 위해서 Binding 을 넣어보죠 !

struct CurrentMessageTextView: View {
    @Binding var message: String // 💫 Binding의 등장

    var body: some View {
        Text(message)
            .padding(.all, 10.0)
            .border(Color.green, width: 2.0)
    }
}

struct ContentView: View {
    // ✔️ CurrentMessageTextView 가 참조하고자 하는 state property
    @State private var message = "안녕하세요. SwiftUI는 어떠신가요"

    var body: some View {
        VStack(spacing: 10.0) {
            CurrentMessageTextView(message: $message) // ⁉️⁉️⁉️⁉️⁉️⁉️
            CurrentMessageTextView(message: $message)
        }
    }
}

– ⁉️ 의 부분에 왜 $이 필요할까요?
– 부모뷰에서는 자식뷰에서 Binding 을 통해 참조만 할 것인지 새로운 값까지 대입시킬 것인지 판단할 수 없기 때문에 사용해야합니다.
개인적으로는 private(set) 처럼 참조만 가능하게 하는 편이 나중의 안전성을 조금 더 보장하지 않았을까 싶기도 하네용


– ContentView 에서 변경한 값이 잘 반영되고 있지요 ~~~ ?
UIKit에서 작성했었던 update 메소드들이 주마등처럼 지나가네요 😭




Observed Object


@ObservedObject 을 사용하기 위해서는 ObservableObject를 만들어야합니다.

두 가지 모두 iOS 13에서 SwiftUI과 함께 Combine 프레임워크에 포함되어 공개되었어요.
그리고 Rx 를 외부 프레임워크 도입없이, 네이티브에서 구현할 수 있게 되었죠.

Combine에 대해서 자세히 설명하게 되면 너무 이야기가 커져버려서 😢
여기서는 View에서 @ObservedObject를 어떻게 사용하고, ObservableObject를 어떻게 만드는지에 대해 알아볼게요 !



ObservableObject는 프로토콜로 정의되어 있어 class로 정의할 수 있어요.

class UserData: ObservableObject {
    @Published var id: Int = 0 // 💫
    @Published var name = "" // 💫

    init() {
        setupData()
    }

    func setupData() {
        // request 할 필요가 있으면 여기에서 실행
        id = 001
        name = "unnnyong"
    }
}

UserData 라는 ObservableObject 를 정의해보았어요.
@Published property 가 눈에 띄죠 ?
– property wrapper 로 정의되어 있고, 값이 변경될 때마다 구독자들에게 업데이트를 알려주는 친구예요.
https://developer.apple.com/documentation/combine/published

struct ContentView: View {
    @ObservedObject var userData = UserData() // 💫

    var body: some View {
        VStack(spacing: 10.0) {
            Text("ID: \(userData.id)")
            TextField("USER NAME", text: $userData.name)
        }
    }
}

– UserData 에서 정의한 @ObservableObject 는 View에서 이렇게 사용된답니다.
– $ 의 사용은 @State property 와 같아요 !


ObservableObject 으로 정의하면 여러가지 View에서 @ObservedObject property로 만들어서 상태를 지속적으로 업데이트하는 값에 대해 사용할 수 있네요.



앱 내에서 UserData는 하나뿐인데 그때마다 초기화 시킬 수도 없고,
하나의 ObservableObject를 여러 View에서 static 으로 사용하기 위해서는 어떻게 해야할까요? 🤔

👇

Environment Object


여러 View 가 동시에 같은 property 에 접근할 때 사용해요.

@EnvirionmentObject var userData: UserData

// UserData.swift
class UserData: ObservableObject {
    @Published var id: Int = 0
    @Published var name = ""

    static let shared = UserData() // 💫

    init() {
        setupData()
    }

    func setupData() {
        // request 할 필요가 있으면 여기에서 실행
        id = 001
        name = "unnnyong"
    }
}

// ContentView.swift
struct ContentView: View {
    @EnvironmentObject var userData: UserData  // 💫

    var body: some View {
        VStack(spacing: 10.0) {
            Text("ID: \(userData.id)")
            TextField("USER NAME", text: $userData.name)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(UserData.shared)  // 💫
    }
}

“SwiftUI | @State, @Binding, @ObservedObject”의 1개의 생각

SwiftUI | Tab View – unnnyong 에 답글 남기기 응답 취소

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중