[내일배움캠프] 251226 TIL

Bambu·2025년 12월 26일

내배캠 TIL

목록 보기
7/52

1. Step 4. Combine

1) Combine이란

Combine : Apple에서 제공하는 반응형 프로그래밍 프레임워크
→ 비동기 이벤트 및 데이터의 처리와 반응형 프로그래밍을 위한 프레임워크

  • Publisher : 데이터를 제공하는 주체
  • Subscriber : Publisher가 제공하는 데이터를 수신하고 처리하는 주체
  • Operators : 데이터를 변환하거나 필터링하는 중간 연산자
  • PublisherOperatorSubscriber의 흐름으로 진행
import Combine

// Publisher 생성 - Combine에서 제공하는 기본 Publisher 프로퍼티 이용
let numbers = [1, 2, 3, 4, 5].publisher

// Subscriber를 통해 값 출력
numbers
	.map { $0 * 2 } // 값 변환 (Operator)
    .sink { print($0) } // 값 출력 - Combine 기본 메소드 sink(receivedValue:)
    
// 2 4 6 8 10 출력

→ Combine에서는 기본적으로 여러 Publisher를 제공
→ Publisher를 subscribe 할 수 있는 두 가지 메소드 또한 제공
: sink(receiveCompletion:receiveValue:)
: assign(to:on:)

⇒ 예제에서는 sink(receiveValue:)를 사용하여 publisher인 numbers가 제공한 값(연산자를 통해 변환된)을 출력

sink 메소드를 통해 subscribe 되었으므로 numbers.map { $0 * 2 }.sink { print($0) } 자체가 Subscriber

참고: [Swift/Combine] Combine Framework - 이정훈님 velog

2) 직접 구현해보기

Step 1: Combine 기본 구현

  • 간단한 Publisher와 Subsciber 만들기
import Foundation
import Combine

// Publisher 생성
let pub = [10, 20, 30, 40, 50].publisher

// Subscriber 생성
pub.map { $0 * 2 } // 중간 연산자 - 값 2배 변환
    .sink { print($0) } // 변환된 값 출력
  • Just Publisher 사용

    💡 Just
    A Publisher that emits an output to each subscriber just once, and then finishes
    → 각 subscriber에 output을 한 차례만 보내고(하나의 output만을 내보내고) 종료되는 publisher

    : publisher 체인의 시작부에 사용할 수 있다.
    : Just publisher는 에러와 함께 실패할 수 없으며, 항상 값을 생성한다.(== 옵셔널 타입이 될 수 없다.)
    참고: Just | Apple Developer Documentation

import Foundation
import Combine

let pub = Just(1)

pub.map { $0 + 50 }
    .sink { print($0) }

// 51 출력

Step 2: Combine으로 비동기 데이터 처리

→ 처음 접하는 개념이라 이해와 구현이 어려워 힌트 그대로 사용하여 이런 코드인 것 같다~를 주석으로 작성...

  • URLSession과 Combine 사용
import Foundation
import Combine

let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")!
var cancellable: AnyCancellable?

cancellable = URLSession.shared.dataTaskPublisher(for: url) // Publisher 생성
    .map { $0.data } // url에서 data만 가져옴
    .decode(type: Todo.self, decoder: JSONDecoder()) // JSON 타입을 디코드
    .sink(
        receiveCompletion: { print("Completion: \($0)") }, // Completion 결과 출력
        receiveValue: { print("Title: \($0.title)") } // 수신 값 출력
    )

// JSON Decode용
struct Todo: Codable {
    var title : String
}
import Foundation
import Combine

let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() // Timer publisher 생성
var cancellable: AnyCancellable? // (구독을) 취소 가능한 무언가..?

cancellable = timer.sink { print($0) } // timer.sink subscriber가 구독을 취소 가능하도록 cancellable에 할당

// main 큐에서 UI(현재 시간 출력) 업데이트, 함수의 deadline이 현재 시간으로부터 5초 뒤
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
    cancellable?.cancel() // deadline 지나면 구독을 취소
}
profile
안녕하세요, iOS 개발을 공부하고 있는 Bambu입니다. (프로필: Swifticons)

0개의 댓글