AsyncPublisher은 간단하고 비동기적으로 Publisher로부터 받는 데이터를 처리하고 싶을 때 사용합니다

 

코드로 이해하기

우선 AsyncPublisherDataManager라는 클래스가 있고 @Published로 선언된 [String] 타입의 데이터가 존재합니다.

addData 메서드를 이용하여 2초마다 데이터를 삽입하며 이것은 비동기적으로 수행됩니다.

class AsyncPublisherDataManager {
    
    @Published var myData: [String] = []
    
    func addData() async {
        myData.append("Apple")
        try? await Task.sleep(nanoseconds: 2_000_000_000)
        myData.append("Banana")
        try? await Task.sleep(nanoseconds: 2_000_000_000)
        myData.append("Watermelon")
        try? await Task.sleep(nanoseconds: 2_000_000_000)
        myData.append("Orange")
    }
}

 

Combine을 사용했을 때

다음으로는 AsyncPublisherViewModel로 위에 데이터를 Combine을 이용하여 데이터를 sink하여 뷰에 보여줄 데이터를 저장할 수 있습니다. init 함수가 실행된 이후 addSubscribers 메서드가 실행되어 데이터를 받아옵니다.

class AsyncPublisherViewModel: ObservableObject {
    
    @MainActor @Published var dataArray: [String] = []
    let manager = AsyncPublisherDataManager()
    var cancellable = Set<AnyCancellable>()
    
    init() {
        addSubscribers()
    }
    
    private func addSubscribers() {
        Task {
            await MainActor.run {
                manager.$myData
                    .receive(on: DispatchQueue.main)
                    .sink { dataArray in
                        self.dataArray = dataArray
                    }
                    .store(in: &cancellable)
            }
        }
    }
    
    func start() async {
        await manager.addData()
    }
}

 

AsyncPublisher를 사용했을 때

물론 위처럼 combine을 사용할 수 있습니다, 하지만 아래 AsyncPublisher를 사용했을 때 얼마나 간편해지는지 확인하면 앞으로도 AsyncPublisher를 사용할 것입니다.

class AsyncPublisherViewModel: ObservableObject {
    
    @MainActor @Published var dataArray: [String] = []
    let manager = AsyncPublisherDataManager()
    
    init() {
        addSubscribers()
    }
    
    private func addSubscribers() {
        Task {
            for await value in manager.$myData.values { // .value = AsyncPublisher
                await MainActor.run {
                    self.dataArray = value
                }
            }
        }
    }
    
    func start() async {
        await manager.addData()
    }
}

 

위에 데이터를 보여주기 위한 View

struct ContentView: View {
    
    @StateObject private var viewModel = AsyncPublisherViewModel()
    var body: some View {
        ScrollView {
            VStack {
                ForEach(viewModel.dataArray, id: \.self) {
                    Text($0)
                        .font(.headline)
                }
            }
        }
        .task {
            await viewModel.start()
        }
    }
}

'SwiftUI' 카테고리의 다른 글

AVFoundation 이용한 음성 녹음하기  (0) 2024.05.30
Sendable 프로토콜  (0) 2024.05.25
MacPaw/OpenAI SwiftUI Package 분석하기  (0) 2024.05.25
Global Actor과 Main Actor  (0) 2024.05.24
Actor  (0) 2024.05.21
ytw_developer