J
[Combine] Scheduler와 비동기 처리 이해하기 본문
Scheduler와 비동기 처리 이해하기
Combine을 실제 프로젝트에서 사용하다 보면,
"어떤 쓰레드에서 이 작업이 실행될까?", "UI 업데이트는 메인에서 해야 하지 않나?"
같은 질문이 생기게 됩니다.
이럴 때 사용하는 것이 바로 Scheduler(스케줄러) 입니다.
이번 글에서는 Combine에서의 쓰레드 처리와 비동기 흐름 제어 방법에 대해 기초부터 차근히 알아보겠습니다.
Scheduler란?
Scheduler는 Combine에서 작업을 어떤 스레드/큐에서 실행할지를 제어할 수 있게 해주는 개념입니다.
즉, 데이터를 발행하거나 받는 시점의 쓰레드를 지정할 수 있습니다.
대표적인 Scheduler 종류
Scheduler | 설명 |
DispatchQueue.main | 메인 스레드 (UI 업데이트에 필수) |
DispatchQueue.global() | 백그라운드 글로벌 큐 |
RunLoop.main | 메인 런루프 (iOS UI 작업용) |
OperationQueue | 커스텀 큐 설정 가능 |
receive(on:) vs subscribe(on:)
이 두 메서드는 비슷해 보이지만 역할이 다릅니다.
✅ receive(on:)
- Subscriber가 데이터를 처리하는 스레드를 지정
- UI 업데이트에 자주 사용 (보통 DispatchQueue.main)
✅ subscribe(on:)
- Publisher가 데이터를 생성하는 스레드를 지정
- 네트워크 요청, 파일 IO 등 작업의 시작 위치에 사용
예제: 비동기 처리 + Scheduler
import Combine
import Foundation
var cancellables = Set<AnyCancellable>()
func loadData() -> AnyPublisher<String, Never> {
return Just("서버에서 받은 데이터")
.delay(for: .seconds(2), scheduler: DispatchQueue.global()) // 백그라운드에서 딜레이
.subscribe(on: DispatchQueue.global()) // 작업 시작 위치
.receive(on: DispatchQueue.main) // UI 업데이트를 위해 메인으로 전환
.eraseToAnyPublisher()
}
loadData()
.sink { value in
print("UI에서 받은 값: \(value) / Thread: \(Thread.isMainThread ? "Main" : "Background")")
}
.store(in: &cancellables)
(약 2초 후)
UI에서 받은 값: 서버에서 받은 데이터 / Thread: Main
- 백그라운드에서 값이 생성되고
- 메인 스레드에서 UI 관련 작업이 수행됨
언제 어떤 Scheduler를 써야 할까?
상황 | 사용하는 Scheduler |
네트워크, 디스크 작업 시작 | subscribe(on: DispatchQueue.global()) |
UI 업데이트 | receive(on: DispatchQueue.main) |
타이머, 입력 debounce | RunLoop.main 또는 DispatchQueue.main |
Debounce와 Scheduler
사용자 입력처럼 빠르게 발생하는 이벤트를 다룰 때는 debounce와 Scheduler 조합이 매우 유용합니다.
let searchText = PassthroughSubject<String, Never>()
searchText
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.sink { keyword in
print("검색어 처리: \(keyword)")
}
.store(in: &cancellables)
- 입력이 멈춘 지 0.3초가 지나야 값을 발행
- 너무 자주 발생하는 이벤트를 필터링하여 리소스 낭비 방지
정리
개념 | 설명 |
Scheduler | 작업이 실행될 스레드를 지정 |
subscribe(on:) | Publisher가 실행될 스레드 지정 |
receive(on:) | Subscriber가 처리할 스레드 지정 |
DispatchQueue.main | UI 업데이트에 필수 |
debounce + Scheduler | 빠른 이벤트 제어에 적합 |
Combine을 제대로 활용하려면 흐름의 시점과 쓰레드를 명확히 구분하는 것이 중요합니다.
특히 SwiftUI, UIKit에서 Combine을 사용할 땐 UI는 항상 메인 스레드에서 처리해야 한다는 점, 잊지 마세요.
'iOS > Combine' 카테고리의 다른 글
[Combine] 에러 처리: tryMap, catch, replaceError (0) | 2025.04.08 |
---|---|
[Combine] Subject와 @Published... SwiftUI 연동까지 (0) | 2025.04.07 |
[Combine] Publisher, Subscriber, Operator, Cancellable (0) | 2025.04.07 |
[Combine] Network 통신 (Upbit API 예제 포함) (0) | 2024.11.12 |