Swift Combine Publisher의 기본 개념과 사용법
다양한 Swift Combine Publisher 사용 예제
Swift Combine은 애플의 리액티브 프로그래밍 프레임워크로, 비동기 이벤트 처리와 데이터 스트림 관리를 위해 설계되었습니다. Combine은 Publisher와 Subscriber로 구성되며, Publisher는 데이터를 발행하는 역할을 합니다. 이 글에서는 다양한 Swift Combine Publisher와 그 사용 예제에 대해 알아보겠습니다.
기본 Publisher 타입
Combine 프레임워크는 다양한 내장 Publisher 타입을 제공하여 다양한 상황에 맞게 사용할 수 있습니다. 주요 Publisher 타입과 그 사용 예제를 살펴보겠습니다.
Just
Just
는 단 하나의 값을 발행하는 Publisher입니다. 오류를 발생시키지 않으며, 매우 간단한 형태의 Publisher입니다.
swiftimport Combine let justPublisher = Just("Hello, Combine!") let cancellable = justPublisher.sink(receiveCompletion: { completion in switch completion { case .finished: print("Finished") case .failure(let error): print("Error: \(error)") } }, receiveValue: { value in print("Received value: \(value)") })
이 예제는 "Hello, Combine!" 문자열을 발행하고 완료를 출력합니다.
Future
Future
는 비동기 작업의 결과를 발행하는 Publisher입니다. 비동기 작업이 완료되었을 때, 결과 값을 한 번 발행하고 종료합니다.
swiftlet futurePublisher = Future<String, Error> { promise in DispatchQueue.global().asyncAfter(deadline: .now() + 1) { promise(.success("Async result")) } } let cancellable = futurePublisher.sink(receiveCompletion: { completion in switch completion { case .finished: print("Finished") case .failure(let error): print("Error: \(error)") } }, receiveValue: { value in print("Received value: \(value)") })
이 예제는 비동기 작업이 완료된 후 "Async result"를 발행합니다.
Deferred
Deferred
는 Subscriber가 구독할 때까지 Publisher의 생성 및 실행을 지연시키는 역할을 합니다. 이를 통해 구독 시점에 Publisher를 동적으로 생성할 수 있습니다.
swiftlet deferredPublisher = Deferred { Just(Date()) } let cancellable = deferredPublisher.sink(receiveValue: { value in print("Received date: \(value)") })
이 예제는 구독 시점에 현재 날짜와 시간을 발행합니다.
Empty
Empty
는 즉시 완료되거나 오류를 발생시키지 않고 아무 값도 발행하지 않는 Publisher입니다.
swiftlet emptyPublisher = Empty<Int, Never>() let cancellable = emptyPublisher.sink(receiveCompletion: { completion in switch completion { case .finished: print("Finished") case .failure: print("Error") } }, receiveValue: { value in print("Received value: \(value)") })
이 예제는 아무 값도 발행하지 않고 완료됩니다.
Fail
Fail
는 특정 오류를 즉시 발행하고 완료되는 Publisher입니다.
swiftenum MyError: Error { case exampleError } let failPublisher = Fail<Int, MyError>(error: .exampleError) let cancellable = failPublisher.sink(receiveCompletion: { completion in switch completion { case .finished: print("Finished") case .failure(let error): print("Error: \(error)") } }, receiveValue: { value in print("Received value: \(value)") })
이 예제는 오류를 발행하고 종료됩니다.
Sequence를 Publisher로 사용하기
Combine은 배열과 같은 Sequence 타입을 Publisher로 변환할 수 있습니다.
swiftlet numbers = [1, 2, 3, 4, 5].publisher let cancellable = numbers.sink(receiveCompletion: { completion in switch completion { case .finished: print("Finished") case .failure(let error): print("Error: \(error)") } }, receiveValue: { value in print("Received number: \(value)") })
이 예제는 배열의 각 요소를 순차적으로 발행하고 완료됩니다.
Timer Publisher
Combine은 주기적으로 값을 발행하는 Timer Publisher도 제공합니다.
swiftlet timerPublisher = Timer.publish(every: 1.0, on: .main, in: .default).autoconnect() let cancellable = timerPublisher.sink(receiveValue: { value in print("Timer fired at: \(value)") })
이 예제는 1초마다 현재 시간을 발행합니다.
NotificationCenter Publisher
NotificationCenter에서 게시된 알림을 Publisher로 사용할 수도 있습니다.
swiftlet notificationPublisher = NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification) let cancellable = notificationPublisher.sink(receiveValue: { notification in print("Received notification: \(notification)") })
이 예제는 앱이 활성화될 때마다 알림을 발행합니다.
URLSession Data Task Publisher
Combine을 사용하여 네트워크 요청도 처리할 수 있습니다.
swiftlet url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")! let dataTaskPublisher = URLSession.shared.dataTaskPublisher(for: url) let cancellable = dataTaskPublisher.sink(receiveCompletion: { completion in switch completion { case .finished: print("Finished") case .failure(let error): print("Error: \(error)") } }, receiveValue: { data, response in print("Received data: \(data)") })
이 예제는 지정된 URL로 네트워크 요청을 보내고, 응답 데이터를 발행합니다.
Operator 활용
Combine에서는 다양한 연산자를 사용하여 Publisher의 데이터를 변환하거나 결합할 수 있습니다. 몇 가지 중요한 연산자를 살펴보겠습니다.
Map
map
연산자는 발행된 값을 변환하는 데 사용됩니다.
swiftlet numbers = [1, 2, 3, 4, 5].publisher let stringNumbers = numbers.map { "\($0)" } let cancellable = stringNumbers.sink { print($0) }
이 코드는 숫자 배열을 문자열 배열로 변환하여 출력합니다.
Filter
filter
연산자는 조건에 맞는 값만을 통과시킵니다.
swiftlet numbers = [1, 2, 3, 4, 5].publisher let evenNumbers = numbers.filter { $0 % 2 == 0 } let cancellable = evenNumbers.sink { print($0) }
이 코드는 짝수만을 통과시켜 출력합니다.
CombineLatest
combineLatest
는 두 개의 Publisher의 최신 값을 결합합니다.
swiftlet publisher1 = PassthroughSubject<String, Never>() let publisher2 = PassthroughSubject<Int, Never>() let combined = publisher1.combineLatest(publisher2) let cancellable = combined.sink { (string, int) in print("Received: \(string) and \(int)") } publisher1.send("A") publisher2.send(1) publisher1.send("B") publisher2.send(2)
이 코드는 각 Publisher의 최신 값을 결합하여 출력합니다.
결론
Swift Combine은 다양한 내장 Publisher와 연산자를 제공하여, 비동기 데이터 스트림을 효과적으로 관리하고 처리할 수 있는 강력한 도구입니다. 다양한 Publisher를 활용하면 복잡한 비동기 로직을 간단하고 명확하게 구현할 수 있으며, 이를 통해 더 나은 사용자 경험을 제공할 수 있습니다. Combine의 기본 사용법과 다양한 예제를 통해 리액티브 프로그래밍의 장점을 최대한 활용해보세요.