
기본
⎮ Combine
- Combine Framework : 애플에서 제공하는 반응형 프로그래밍(Reactive Programming) 프레임워크
* 데이터의 흐름을 선언적으로 처리하고 비동기적으로 처리할 때 사용
사용 예) 네트워크 요청, 사용자 입력, 타이머 등과 같은 비동기 이벤트
- 주요개념
발행자(Publisher) : 데이터를 제공하는 주체. 데이터가 발생하거나 변경될 때 이벤트를 발행
예) 네트워크 요청 결과, 사용자 입력 이벤트, 타이머 등
구독자(Subscriber) : 데이터를 수신하고 처리하는 주체. Publisher가 발행하는 데이터를 받아서 처리하는 역할
예) UI에 값을 표시, 처리 결과 출력 등
연산자(Operators) : Publisher와 Subscriber 사이에서 데이터를 변환하거나 필터링하는 중간 처리 역할
예) 값을 변경하거나 조건에 맞는 값만 필터링
- Combine의 흐름
Publisher(데이터 발행) → Operator(데이터 변환, 필터링) → Subscriber(데이터를 최종적으로 처리
import Combine
// Publisher 생성
let numbers = [1, 2, 3, 4, 5].publisher
// Subscriber를 통해 값 출력
numbers
.map { $0 * 2 } // 값 변환
.sink { print($0) } // 값 출력
실습
⎮ Combine 기본 구현
간단한 Publisher와 Subscriber 만들기 :
- 배열 [10, 20, 30, 40, 50]을 Publisher로 생성하고, 각 값을 2배로 변환한 후 출력하세요.
import Combine
let numbers = [10, 20, 30, 40, 50].publisher
numbers
.map { $0 * 2}
.sink { print($0) }
/*
20
40
60
80
100
*/
Just Publisher 사용:
- 단일 값 100을 제공하는 Just를 사용하여 값을 변환(+50)하고 출력하세요.
let justPublisher = Just(100)
justPublisher
.map { $0 + 50 }
.sink { print($0) }
// 150
⎮ Combine으로 비동기 데이터 처리하기
URLSession과 Combine 사용:
- Combine을 사용해 네트워크 요청을 수행하고 결과를 출력하세요.
- API: https://jsonplaceholder.typicode.com/todos/1
- 요청 결과의 title 값을 출력하세요.
import Combine
import Foundation
let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")!
var cancellable: AnyCancellable?
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data } // 네트워크 응답에서 'data' 부분만 추출
.decode(type: Todo.self, decoder: JSONDecoder()) // 'data'를 'Todo' 모델로 디코딩
.sink(
receiveCompletion: { print("Completion: \($0)") }, // 네트워크 요청 완료 처리
receiveValue: { print("Title: \($0.title)") } // 'title'을 출력
)
struct Todo: Codable {
let title: String
}
코드를 뜯어보자
// 필요한 라이브러리 가져오기
import Combine
import Foundation
Combine 프레임워크를 가져와서 비동기 데이터 흐름을 관리,
Foundation 표준 라이브러리를 가져와서 기본적인 데이터 처리, 네트워크 요청, 시간 처리 등의 작업 수행
// URL 생성
let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")!
요청할 API 주소로 url 객체를 생성, 강제 추출 연산자를 사용하여 언래핑
// 객체 생성
var cancellable: AnyCancellable?
구독을 취소할 수 있는 cancellable 객체 생성
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data } // 네트워크 응답에서 'data' 부분만 추출
.decode(type: Todo.self, decoder: JSONDecoder()) // 'data'를 'Todo' 모델로 디코딩
.sink(
receiveCompletion: { print("Completion: \($0)") }, // 네트워크 요청 완료 처리
receiveValue: { print("Title: \($0.title)") } // 'title'을 출력
)
- URLSession.shared.dataTaskPublisher(for: url) : 지정된 URL로 GET 요청을 보내고, 그 결과를 비동기적으로 처리
URLSession : iOS에서 HTTP 요청을 처리하는 객체
dataTaskPublisher(for:) : URLSession에서 제공하는 Combine Publisher.
네트워크 요청을 실행하고, 그 결과로 data와 response를 튜플로 반환
- map { $0.data } : 튜플로 반환된 값 중 data만 추출
- decode(type: Todo.self, decoder: JSONDecoder()) : JSON 디코딩
Todo.self : Todo 모델로 데이터를 디코딩
JSONDecoder : JSON 데이터를 Swift의 객체로 변환해주는 클래스(서버로부터 받은 JSON 데이터를 디코딩
- sink : Subscriber. 여기서는 2개의 클로저를 전달
- receiveCompletion : 요청이 완료되었을 때 호출되는 클로저. (finished 또는 failure 상태를 포함)
- receiveValue : 요청이 성공하고, 디코딩된 Todo 객체가 전달되면 호출되는 클로저
struct Todo: Codable {
let title: String
}
Todo 구조체는 Codable 프로토콜을 채택한 모델.
- Codable : 디코딩(JSON → 객체)과 인코딩(객체 → JSON)을 자동으로 처리
Timer Publisher 사용:
- 1초마다 현재 시간을 출력하는 Combine 타이머를 생성하세요.
- 5초 후에는 구독을 취소하세요.
import Combine
let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
var cancellable: AnyCancellable?
cancellable = timer
.sink { print($0) } // 타이머 발행 이벤트를 출력
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
cancellable?.cancel() // 5초 후 구독 취소
}
코드를 뜯어보자
let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
- Timer.publish : 주기적인 이벤트를 발생시키는 Publisher를 생성
- every: 1.0 : 1초마다 이벤트를 발행(매 1초마다 Date 객체를 방출)
- on: .main : 타이머의 실행 위치 (메인 스레드에서 실행)
- in: .common : 타이머가 런루프의 common 모드에서 실행되도록 설정(UI 이벤트와 타이머가 동시에 실행될 수 있도록)
- autoconnect() : 타이머 Publisher를 자동으로 연결(이 코드가 실행되는 즉시 타이머가 시작)
var cancellable: AnyCancellable?
cancellable = timer
.sink { print($0) } // 타이머 발행 이벤트를 출력
- sink : Subscriber
- print($0): 타이머에서 발행된 Date 값을 출력 (2025-02-25 12:00:00 +0000와 같은 형식으로 출력)
- cancellable : AnyCancellable 타입의 변수, 나중에 타이머의 구독을 취소할 수 있도록 만든 것
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
cancellable?.cancel() // 5초 후 구독 취소
}
- DispatchQueue.main.asyncAfter : 주어진 시간 뒤에 비동기적으로 특정 작업을 실행하도록 예약
- .now() + 5 : 현재 시점에서 5초 뒤
- cancellable?.cancel() : 5초 후 타이머 Publisher의 구독을 취소
'스파르타코딩 클럽 > 사전 캠프' 카테고리의 다른 글
| 14. 스파르타 코딩클럽 [사전캠프 - 비동기 프로그래밍 / 제네릭] (0) | 2025.02.20 |
|---|---|
| 13. 스파르타 코딩클럽 [사전캠프 - 클로저 / 객체지향 프로그래밍] (0) | 2025.02.19 |
| 12. 스파르타 코딩클럽 [사전캠프 - 자료구조/메모리 구조 및 ARC] (0) | 2025.02.09 |
| 11. 스파르타 코딩클럽 [사전캠프 - Struct와 Class/Protocol] (1) | 2025.02.08 |
| 10. 스파르타 코딩클럽 [사전캠프 - 가위바위보 게임 만들기] (1) | 2025.02.07 |