iOS 개발 기록

[Combine] Combine과 Combine의 구성 요소 본문

SwiftUI/Combine

[Combine] Combine과 Combine의 구성 요소

택꽁이 2023. 3. 8. 16:31
728x90
📄

Combine이란?

  • 이벤트 처리 연산자들을 결합하여 비동기 이벤트들을 원하는대로 처리하기 위한 프레임워크.
  • Publisher 프로토콜을 통해 시간의 흐름에 따른 데이터 핸들링이 가능하다.
  • Subscriber를 통해 값을 전달 받을 수 있으며, Publisher는 Subscriber가 구독하여 값을 요청할 때에만 데이터를 방출한다.

왜 Combine?

  • 높은 가독성 : Combine으로 선언형 프로그래밍이 가능하다.
  • 비동기 처리의 일원화 : GCD, KVO, Delegate, Notification, Closures 등 다양한 비동기 처리 방식을 일원화 할 수 있다. 참고로 애플은 이들을 대체하는게 아니라 같은 형태의 인터페이스로 만들어주는 거라 한다.
    func publisher(
        for name: Notification.Name,
        object: AnyObject? = nil
    ) -> NotificationCenter.Publisher
    
    // 사용 예
    let noti = NotificationCenter.default
    .publisher(for: UIDevice.orientationDidChangeNotification)
    .sink() { _ in 
    	print("화면 돌아감")
    }
  • Testable : 입출력만 체크하면 되기 때문에 UnitTest에 용이하다.

Combine의 구성 요소

Upstream, Downstream

  • 데이터의 흐름을 표현하기 위해 stream이라는 용어를 사용.
  • 현재 처리하고 있는 시점보다 이전이면 upstream, 이후면 downstream

Publisher

  • 값과 에러를 만들어내는 방법이 정의되어 있는 프로토콜.
    // Publisher의 정의
    protocol Publisher<Output, Failure>
  • Publisher는 내부의 receive()를 호출하고 subscriber의 receive(subscription:)과 같은 메소드로 구독을 전달한다.
    struct pub: Publisher {
      typealias Output = Int
      typealias Failure = Error
      
      func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Int == S.Input {
    		// 구현 부분  
    	} 
    }
  • Publisher를 직접 커스텀해서 만드는 것을 권장하지 않는다. 대신에 프레임워크에서 제공하는 Subject@Published 등을 사용하여 나만의 Publisher를 만들 수 있다.
  • 그 외에도 다음과 같은 간편한 Publisher들이 있다.
    // 하나의 값을 방출
    final class Future<Output, Failure> where Failure : Error
    
    // Output 값을 한번만 출력한 후 완료. 에러에 의해 절대로 실패할 수 없다. 에러 타입 Never
    struct Just<Output>
    
    // 구독까지 대기 타다가 구독하면 Deferred 클로저가 실행
    struct Deferred<DeferredPublisher> where DeferredPublisher : Publisher
    
    // 값을 방출하지 않고 즉시 완료.
    struct Empty<Output, Failure> where Failure : Error
    
    // 바로 Fail 보냄
    struct Fail<Output, Failure> where Failure : Error
    
    // 나중에 값을 내보낼 수 있도록 저장해두는 input과 completion 을 저장해두는 publisher
    // 인스턴스화 할 때 값을 설정할 수 있으며, 이후에 값을 넣을수 업
    struct Record<Output, Failure> where Failure : Error
    
    // 업스트림의 데이터를 전달하기 위한 가장 추상화 된 Publisher.
    @frozen struct AnyPublisher<Output, Failure> where Failure : Error

Subscriber

  • Publisher로 부터 값을 받아 사용하는 객체가 따라야 하는 프로토콜.
  • Subscriber을 custom하려면 Publisher의 Output과 Failure와 Subscriber의 Input과 Failure가 같아야 하며, 아래의 메서드들을 구현해야 한다.
    // 성공적으로 구독했음을 알리고, publisher에게 아이템을 요청(request)한다.
    func receive(subscription: Subscription) {
    	print("구독 시작")
    	subscription.request(.unlimited)   // 데이터 개수에 제한을 두지 않음.
    }
    
    // publiser가 값을 생성했다고 subscriber에 알림
    // input에 따라 swiftch로 더 받을지 말지 결정할 수 있음 (누적형태)
    func receive(_ input: Int) -> Subscribers.Demand {
    	print("구독 수신: \(input)")
      return .none
    }
    
    // publisher에게 정상적으로, 혹은 오류로 완료했다고 알림
    func receive(completion: Subscribers.Completion<Never>) {
      print("발행 끝!", completion)
    }
  • 일반적으로 sinkassign의 메소드를 통해 구독하는 것 같다.
    // 커스텀한 subscriber를 사용할 때.
    let publisher = [1, 2, 3, 4].publisher
    publisher.subscribe(taekSubscriber)   
    
    // AnyCancellable타입 반환, 주어진 클로저 실행
    let sink = [1, 2, 3, 4].publisher
    						.sink { print($0) }
    
    // AnyCancellable 타입 반환, 주어진 publisher에 key-path를 통해 바인딩
    let assign = [1, 2, 3, 4].publisher
    						.assign(to: /.value, on: self)

Combine이 데이터를 다루는 과정

Combine이 데이터를 다루는 과정

다른 비동기 처리 방법과 비교

vs RxSwift

  • 성능상 Combine이 더 좋다.
  • 그런데 iOS13부터 지원인게 약점. Target number가 올라갈수록 Combine을 채택하는 경우가 많아질 것 같다.

vs SwiftConcurrency

  • Swift5.5에서 등장한 SwiftConcurrencyasync/await와 함께 비동기 이벤트들을 처리하기에 적합하다.
  • 그러나 Combinedebounce(for:scheduler:options:)throttle(for:scheduler:latest:)와 같은 시간에 기반한 연산이나 merge(with:)combineLatest(_: _:)와 같은 결합 연산을 제공한다고 한다.

참고

Apple Developer Documentation
https://developer.apple.com/documentation/combine/publisher

Combine 시작하기(1)-Overview
애플은 WWDC 2019에서 Combine이라는 새로운 API를 발표했습니다. 이는 기존에 많이 쓰이고 있던 Rx와 같은 포지션에 있었기 때문에 더욱 더 많은 관심을 끌었습니다. 비록 최소 버전이 iOS 13 이기 때문에 당장 도입하기는 어렵지만, 이후의 변화에 적응하기 위해서 미리 공부를 시작해보고자 합니다. Combine은 무엇인가? Apple은 Combine에 대해서 이렇게 정의하였습니다. A Unified, declarative...
https://jcsoohwancho.github.io/2020-01-18-Combine-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0(1)-Overview/


Uploaded by N2T

'SwiftUI > Combine' 카테고리의 다른 글

[Combine] Subscribe vs Receive  (0) 2023.03.08