SwiftUI의 onReceive

June·2023년 2월 24일
0

SwiftUI-Data

목록 보기
9/12
post-thumbnail

onReceive

  • 관찰된(Observe) 객체의 게시자(Publisher)가 값을 변경할 때 코드를 실행하고 싶다면, onReceive를 사용.
class OnReceiveClass: ObservableObject {
    @Published var data: [String] = []      // View는 @Published속성이 언제 변경되는지 알고싶어한다.
    func fetchData() {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) { [self] in
            data = ["Datum 1", "Datum 2", "Datum 3"]
        }
    }
}

struct OnReceive: View {
    @StateObject var onRecevieClass = OnReceiveClass()
    @State private var isProcessing = true
    
    var body: some View {
        VStack(spacing: 20) {
            CommonTextView(title: "onReceive", desc: "관찰된(Observe) 객체의 게시자(Publisher)가 값을 변경할 때 코드를 실행하려면 onReceive 사용")
            
            ZStack {
                List(onRecevieClass.data, id: \.self) { datum in
                    Text(datum)
                }
                
                if isProcessing {
                    ProgressView()
                }
            }
        }
        .onAppear {
            onRecevieClass.fetchData()
        }
        .onReceive(onRecevieClass.$data) { _ in     // $의 위치 주목. $는 속성의 게시자(Publisher)를 보여줌.
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
                isProcessing = false
            }
        }
    }
}

Publisher 출력

class OnReceiveClass: ObservableObject {
    @Published var name = "June"
}

struct OnReceivePublisherOutput: View {
    @StateObject var onReceiveClass = OnReceiveClass()
    @State private var originValue = "June"
    @State private var nameText = ""
    @State private var disabled = true
    
    var body: some View {
        VStack(spacing: 20) {
            CommonTextView(title: "onReceive", desc: "onReceive의 클로저 매개변수로, Publisher가 보낸 데이터 검사함")
            
            TextField("이름 입력", text: $onReceiveClass.name)
                .textFieldStyle(.roundedBorder)
                .padding()
            
            Button("저장하기") {
                originValue = onReceiveClass.name
            }
            .disabled(disabled)   // 데이터가 변경된 경우에만 저장 버튼 활성화
            .onReceive(onReceiveClass.$name) { newValue in
                disabled = (newValue == originValue)    // 클로저에서 매개변수로 받은 새 값(newValue)를 검사할 수 있음.
            }
        }
    }
}

OnReceiveClass 내부에서 Publish중인 name 속성의 변화를 감지해, name 속성이 직전의 값과 차이가 있는 경우에만 '저장하기' 버튼이 활성화되는 코드.


EnvironmentObject와 onReceive 함께 사용하기

class UserModel: ObservableObject {
    @Published var username = "June"
    
    // showAsOnline 속성의 변경 사항 추적중. 
    // 변경된 경우 값을 비교해 UI에 다시 연결하는 옵션을 표시함.
    @Published var showAsOnline = true
}

struct onReceiveWithEnvironmentObject: View {
    @EnvironmentObject var user: UserModel
    @State private var reconnect = false
    
    var body: some View {
        VStack(spacing: 15) {
            CommonTextView(title: "onReceive", desc: "onReceive를 사용해 global environment object(전역 환경 객체) 변경에도 대응")
            
            Button(reconnect ? "" : "연결 끊기") { user.showAsOnline = false }
            
            Spacer()
            
            if reconnect {
                HStack {
                    Text("연결 끊어짐")
                        .frame(maxWidth: .infinity, alignment: .leading)
                    Button {
                        user.showAsOnline = true
                    } label: {
                        Text("연결하기")
                    }
                    .buttonStyle(.borderedProminent)
                }
                .padding()
                .background(Color.red)
            }
        }
        .onReceive(user.$showAsOnline) { online in
            if online == false {
                reconnect = true
            } else {
                reconnect = false
            }
        }
    }
}
  • onReceive를 통해 ObservableObject의 변경 사항을 추적
  • 실제로 NotificationCenter의 메시지를 포함한 Publisher의 모든 항목 추적 가능
profile
안다고 착각하지 말기

0개의 댓글