본문 바로가기
이모저모/SwiftUI

웹 통신과 ObservedObject, StateObject

by ARpple 2024. 2. 20.

문제점

💡 뷰를 푸시 즉시 API 호출을 통해 결제할 수 있는 상품 아이템 리스트를 가져오는 뷰
     분명 아이템 배열이 표시가 되었지만 바로 사라지는 문제 발생

원하는 모습..!

문제 가능성

  • API 통신이 2번 된다. (X)

⇒ print가 한번만 일어났다.

case .lists(let response):
                print("list 받기 \(response)")
                Task{@MainActor in
                    self.payAmountList = response
                }

  • 뷰 모델에 list가 2번 set된다. (X)

⇒ didSet으로 추적한 결과 한번만 일어났다.

@MainActor @Published var payAmountList: [PayAmountResponse] = []{
        didSet{print("amountList:",payAmountList)}
    }


View에 onChange를 이용해서 추적

🚨 분명 뷰 모델의 값은 1번만 바뀌었는데 2번 변경이 일어났다

문제 정의

뷰에서 뷰 모델의 추적이 제대로 되지 않는다. (데이터 정합성 문제)

  • Swift Concurrency Actor 문제 (X)

⇒ 모든 값 할당을 MainActor에서 진행함

  • SwiftUI Observing 관련 문제
⇒ 뷰 모델 Observing 프로퍼티를 StateObject로 바꿈 ✅

문제 원인

문제의 뷰 구조

struct PayView: View{
    @ObservedObject var vm: PayVM
...
    var body: some View{
        ZStack{
            listView
            if vm.isPayment {
                paymentView.frame(width: 0, height: 0).opacity(0)
                    .onBackgroundDisappear({
                        vm.action(type: .closePay)
                    }).environmentObject(vm)

            }
          }
        }
    @ViewBuilder var listView: some View{
            ...
            Section {
        ForEach(vm.payAmountList){ payAmount in
                    ...
                }
            ...
    }
}
  • 아이템 리스트(payAmount)를 표시하는 뷰를 ZStack으로 감싸고 있었다.
  • 그 결과 뷰 모델에서 아이템 리스트 값이 바뀐 후, 상위 뷰에 있는 모든 데이터가 Re-Rendering 된다.
    ⚠️ 이 말은 뷰 모델에서 사용한 아이템 배열 값이 초기화 되어서 리스트를 뷰에 보여준다는 것이다.
  • 순서가 다음과 같이 진행하는 것이다.
    1. API를 통해 배열이 변경된다.
    2. 이 배열 값을 사용하는 리스트 뷰에서 변화를 준다.
    3. ObservedObject는 하위 뷰에서 사용하는 값만 변화가 생겨도 전체 뷰를 다시 그리는 역할을 한다.
      ⇒ 초기화를 진행한다.
    4. 이로 인해, 이 뷰에서 사용하는 아이템 배열은 빈 배열이 된다.

문제 확인

사실 이 뷰 리스트 첫 번째 섹션에 있는 현재 코인 개수는 고정 값이었다.
✅ 이 값 또한, ObservedObject, 네트워크 통신을 통해서 나타내 보자

...
(Text("🌱 현재 보유한 코인") + Text(" \(vm.nowPossessionCoin)개")
    .foregroundColor(.accentColor)).font(FontType.bodyBold.font)
...

기본 값 0으로 떨어지는 모습

StateObject로 변경 후 결과

 

StateObject | Apple Developer Documentation

A property wrapper type that instantiates an observable object.

developer.apple.com

✅ 뷰 모델에서 받은 데이터 그대로 값이 나타난다

댓글