본문 바로가기

학습 노트/Swift UI (2022)

25. StateObject

@StateObject


 

 

Apple Developer Documentation

 

developer.apple.com

struct StateObject_Tutorials: View {
    @State private var color: Color = Color.gray

    var body: some View {
        VStack {
            NumberView()
                .frame(width: 200, height: 200)
                .background(color)
                .clipShape(Circle())

            Button {
                color = Color(white: Double.random(in: 0.5 ... 1.0), opacity: 1.0)
            } label: {
                Text("Change Color")
            }
            .padding()
        }
    }
}

코드는 'Change Color' 버튼을 누를 때마다 State 변수로 NumberView의 배경 색을 무작위로 변경한다.

struct NumberView: View {
    @ObservedObject var generator = RandomNumberGenerator()

    var body: some View {
        Text("\(generator.number)")
            .font(.largeTitle)        
    }
}

NumberView는 ObservedObject인  generator의 number 속성을 표시하고,

class RandomNumberGenerator: ObservableObject {
    @Published var number: Int

    init() {
        number = Int.random(in: 1 ... 100)
        print(#function, self)
    }

    deinit {
        print(#function, self)
    }
}

gnerator의 number 속성은 RandomNumberGenerator에서 무작위로 생성된다.

문제는 View의 색을 바꾸기 위해 'Change Color' 버튼을 누르면 NumberView의 숫자가 함께 바뀌는 부분이다.

State 변수인 color를 변경했으므로 NumberView의 background가 변경된다.
이 과정에서 SwiftUI는 View를 다시 그리게 되는데,
이때 NumberView가 '초기화' 되면서 ObservedObject로 선언된 RandomNumberGenerator가 함께 초기화되며,
새로운 무작위 수가 저장 되게 된다.

따라서 버튼을 누를 때마다 RandomNumberGenerator가 init과 deinit을 반복하는 것을
콘솔에서 확인할 수 있다.

복잡한 이야기지만 이는 여러 View가 너무 의존적인 상태에 있기 때문에 발생한 문제로 이를 위해 SwiftUI는
'StateObject'를 제공한다.

struct StateObject_Tutorials: View {
    @State private var color: Color = Color.gray

    var body: some View {
        VStack {
            NumberView()
                .frame(width: 200, height: 200)
                .background(color)
                .clipShape(Circle())

            Button {
                color = Color(white: Double.random(in: 0.5 ... 1.0), opacity: 1.0)
            } label: {
                Text("Change Color")
            }
            .padding()
        }
    }
}
struct NumberView: View {
    @StateObject var generator = RandomNumberGenerator()

    var body: some View {
        Text("\(generator.number)")
            .font(.largeTitle)        
    }
}
class RandomNumberGenerator: ObservableObject {
    @Published var number: Int

    init() {
        number = Int.random(in: 1 ... 100)
        print(#function, self)
    }

    deinit {
        print(#function, self)
    }
}

간단하게 ObservableObject로 선언된 부분을 StateObject로 변경해 주기만 하면 된다.

버튼을 눌러 View의 배경색이 바뀌는 것과 다르게 숫자는 바뀌지 않고,
관련된 log도 콘솔에 나타나지 않는다.

'학습 노트 > Swift UI (2022)' 카테고리의 다른 글

27. List #2  (0) 2022.11.09
26. List #1  (0) 2022.11.04
24. Observable Object & Environment Object  (0) 2022.11.01
23. State & Binding  (0) 2022.10.27
22. NavigationView & TabView  (0) 2022.10.25