Swift Combine은 또 뭐야 ..?

2020. 9. 4. 14:53iOS/Swift

포스팅을 위해 하이에나 처럼 여러 곳을 돌아 다니다가 Combine 이라는 것을 발견했습니다..

띠용 .. ! 이거슨 ..?!

애플 개발자 문서 를 보시면 다음과 같이 나와 있어요 !! 번역해 보자면

'Combine' 프레임워크는 시간이 지남에 따라 값을 처리하기 위한 선언적 스위프트 API를 제공한다. 이러한 값은 여러 종류의 비동기 이벤트를 나타낼 수 있습니다. 게시자를 결합하여 시간이 지남에 따라 변경될 수 있는 값을 노출시키고, 가입자는 게시자로부터 해당 값을 수신합니다.

라고 되어 있습니다. 비동기 이벤트 ..?! publisher ??? subscriber ???? 이거 어디서 많이 봤죠 ..? 이거 완전 RxSwift 아니냐구~

Apple 에서 직접 만든 Reactive 프로그래밍을 위한 프레임 워크라고 하네요. iOS 13 이상 버전부터 사용이 가능하며 Rx와는 다르게 따로 패키지를 받는 것이 아니라 자체적으로 내장된 프레임워크라고 합니다. 그렇기 때문에 시간이나 메모리 할당 면에서 성능이 더 좋다고도 하네요

또한 SwiftUI와 UI바인딩을 하도록 설계되어졌다고 합니다. (더더욱 SwiftUI에 대해 궁금해 지네요)

이 Combine에대해 오늘은 간단하게 훑어보는 시간을 가져보도록 하겠습니다.

굵직하게 봤을 때 Combine 을 이루는 프로토콜을 보면 Publisher, Cancellable, Subscriber, Subject, Scheduler 가 존재합니다 하나씩 훑어 볼계요 ~~

Publisher

Publiser 에 대해서는 다음과 같이 소개해 드리고 있습니다.

Publisher는 하나 이상의 Subscriber 인스턴스로 요소를 전달합니다. subscriber의 Input 및 Failure 관련 타입은 게시자가 선언한 Output 및 Failure 타입과 일치해야 합니다. Publisher는 subscriber를 받기 위해서 receive(subscruber:) 방식을 구현해야 한다.

Publisher는 간단하게 생각했을 때 Rx의 Observable이라고 보시면 됩니다.하지만 Publisher는 프로토콜로 존재하기 때문에 바로 사용할 수는 없고, Publisher를 채택하는 struct 또는 class를 자체적으로 생성하거나, 자체적으로 Combine Framework에 내장되어 있는 AnyPublisher나 Convenience Publisher로 정의되어 있는 Future, Just, Deferred, Empty, Fail, Record 를 사용할 수 있습니다. 이들에 대해서는 다음번에 자세하게 다뤄보도록 하겠습니다.

따라서 Rx에서 사용하는 Observable은 Combine에서 AnyPublisher와 같다고 볼 수 있습니다. 이 둘의 차이 점은 Observable은 생성할 때 Observable과 같이 데이터 타입만을 지정해 주어 사용하지만 AnyPublisher는 데이터 타입 뿐만 아니라 에러 타입까지 지정해주어서 AnyPublisher<String, Error> 와 같이 사용할 수 있습니다.

Cancellable

다음으로는 Cancellable입니다. Cancellable 또한 프로토콜인데요. 이를 자체적으로 구현하여 사용하거나 Swift에서 자체적으로 제공하는 AnyCancellable을 사용할 수도 있다고 합니다. 이는 이제 Rx에서 Disposable과 비슷한 기능을 합니다. deinit 될 때 자동으로 cancel이 된다고 합니다, 그러나 Rx의 Disposebag 같은 개념은 없다고 하네요 ~! 그래서 이제 임의로 생성해서 넣어준다고 하네여 ~!!

Subscriber 

다음으로 중요한 Subscriber인데요 ~!1 Subscriber에 대해 애플 개발자 문서에서는 다음과 같이 소개하고 있습니다.

Subscriber 인스턴스는 Publisher로부터 요소의 Stream을 수신하며, 관계의 변화를 설명하는 라이프 사이클 이벤트도 함께 수신한다. 주어진 Subscriber의 Input 및 Failure 관련 유형은 해당 게시자의 출력 및 실패와 일치해야 한다.

Subscriber는 크게 3가지로 구현할 수 있다고 합니다. 

첫 째로는 Subscriber를 상속받아 직접 구현하기 입니다. Subscriber 또한 프로토콜로 정의되어 있기 때문에 Swift에서 제공하는 자체 Subscriber를 사용할 수도 잇지만,  직접 구현할 수도 있는데요 직접 구현하면서 이 Combine Stream의 라이프 사이클에 대해 대략적으로 확인해 볼 수 있어요 ~~!

class CustomSubscrbier: Subscriber{

    func receive(completion: Subscribers.Completion<Never>) {
        print("End")
    }

    func receive(subscription: Subscription) {
        print("Start")
        subscription.request(.unlimited)
    }

    func receive(_ input: String) -> Subscribers.Demand {
        print("\(input) 최고!!")
        return .none
    }
    
    typealias Input = String //성공타입
    typealias Failure = Never //실패타입
    
}

Subscriber를 구현할 때는 다음과 같이 3가지 메소드를 정의해주어야 합니다. 위에서부터 살짝식 살펴보면

func receive(completion: Subscribers.Completion<Never>) 는 모든 데이터의 발행이 완려된 경우 호출되는 함수입니다.

func receive(subscription: Subscription)는 이제 Subscriber에게 Publisher를 성공적으로 구독했음을 알리고 아이템을 요청할 수 있습니다.

func receive(_ input: String) -> Subscribers.Demand는 이제 Subscriber에게 Publisher가 element를 생성했음을 알리는 이벤트 입니다.

따라서 이제 Publiser에 다음과 같이 등록을 해주면

let publisher = ["이주혁","김남수","김현지","이승호","최담","오준현","윤동민"].publisher

let subscriber = CustomSubscrbier()
publisher.subscribe(subscriber)
Start
이주혁 최고!!
김남수 최고!!
김현지 최고!!
이승호 최고!!
최담 최고!!
오준현 최고!!
윤동민 최고!!
End

다음과 같이 Publisher의 요소들을 받아올 수 있습니다.

그렇지만 이제 매번, 모든 스트림에 대응되는 Subscriber를 만들기란 귀찮은 일이죠 ~!!

그래서 Publisher 내부에서 Subsrber를 생성해 줄수 있는 함수가 있습니다.바로 sink 라는 함수 인데요 !

잠깐 들여다 보면

func sink(receiveCompletion: @escaping ((Subscribers.Completion<Never>) -> Void), receiveValue: @escaping ((ClosedRange<Int>.Element) -> Void)) -> AnyCancellable

다음과 같이 정의되어 있습니다. 파라미터인 receiveCompletion과 receiveValue은 클로져 형태로 받을 수 있으며 보이는 바와 같이 publisher를 통해 전달된 element를 받아오거나, 전달이 완료된 경우 동작에 대해 구현해 줄 수 있습니다.

let publisher = ["이주혁","김남수","김현지","이승호","최담","오준현","윤동민"].publisher

publisher.sink(receiveCompletion: { completion in
    print(completion)
}, receiveValue: { s in
    print("\(s) 최고 !!!")
})
이주혁 최고 !!!
김남수 최고 !!!
김현지 최고 !!!
이승호 최고 !!!
최담 최고 !!!
오준현 최고 !!!
윤동민 최고 !!!
finished

 

우선 오늘은 Publiser와 Subscriber에 대해 중점적으로 알아보는 시간을 가졌습니다. ! 정말 보면서 Rx와 비슷하다는 생각을 많이 했는데요 ~!!! 점점 SwiftUI가 기대되는데요 어떤식으로 발전해 나갈지 정말 궁금합니다. 그렇다고 이 Combine이 스유에서만 적용이 된다는 것은 아니니까 간단하게 Rx 써야할 때 Combine으로 한번 해보는 것도 괜찮을 것 같아요 ㅎ -이상 Rx한번도 한써본사람

기회가 된다면 Subject 프로토콜과 여러 Operator에 대해 알아보는 시간을 가져보도록 하겠습니다.

'iOS > Swift' 카테고리의 다른 글

UIBezierPath 사용해보기  (0) 2020.10.16
KVO에 대해 알아보고 적용해 보자 !!  (0) 2020.08.07
Swift Lint 사용해보기 !!  (2) 2020.04.10