iOS/Swift

Combine은 무엇인가.(비동기 연산 처리 지원 프레임워크)

StudySpare 2022. 1. 20. 13:49
반응형

 

요즘 iOS 개발, 그 중에서도 Swift 언어로 개발하는 곳에는 Combine이 핫한 이슈인 것 같다. 여기저기서 "이제 combine을 적용해야 하는데...", "combine으로 넘어가야겠어." 라는 소리가 들린다. 어렴풋이 저기 어딘가 있는 Combine을 한번 알아봤다.

 

WWDC2019에서 처음 소개된 Combine은 iOS13버전 부터 사용이 가능하다.

아래는 Apple Developer 사이트에서 제공하는 Combine 에 대한 설명이다. 가져와서 한글로 옮겨봤다.


Combine

event-processing operator (이벤트 처리 연산자)를 결합(combining)해서 비동기 이벤트를 입맛에 맞게 핸들링하도록 하는 프레임워크.

  • iOS 13.0+ 
  • iPadOS 13.0+ 

 

요약

Combine 프레임워크는 처리시간이 긴 작업을 처리하는 Swift API이다. 이러한 작업은 대부분은 비동기 이벤트이다. Combine에서는 처리시간이 긴 작업(이벤트)을 변경할 수 있는 publisher와 publisher로부터 작업(이벤트)를 전달 받을 수 있는 subscribe를 선언해두었다.

  • Publisher 작업시간이 긴 일련의 순서가 있는 이벤트들을 전달하기 위한 프로토콜이다. Publisher는 publisher에서 동작하는 값을 받거나 그 값은 다시 배포(republish)하기 위한 연산자들이 정의되어있다.
  • publisher 체인의 끝에서는 Subscriber 값을 받아서 가지고 있는다. Publisher는 subscriber가 요청한 경우에만 값을 제거할 수 있다. 그러면 Subscriber 코드가 자신과 연결된 publisher로 부터 이벤트 받는 속도를 제어할 수 있다.

TimerNotificationCenter, URLSession등과 같은 몇몇 Foundation 타입은 publisher에서 사용할 수 있다. Combine은 또한 Key-Value Observing을 따르는 프로퍼티에 사용할 수 있는 publisher를 내장하고 있다.

여러 publisher로 부터 아웃풋을 조합하고, publisher간 상호작용을 조정할 수 있다. 예를 들어, text field 의 값을 업데이트하기 위해서 text field의 publisher를 subcribe할 수 있고, 그렇게해서 얻은 text field의 text를 이용해서 URL Request를 요청할 수 있다. 그리고 또 다른 publisher를 써서 응답을 처리하고, 앱을 반영할 수 있다.

Combine을 사용함으로써 보다 읽기 쉽고, 유지보수하기 용이한 코드를 작성할 수 있다. 이벤트를 처리하는 코드를 모으고, 중첩된 closure나 전통적으로 사용되던 callback과 같은 기술에서 발생하기 쉬운 비동기 문제들을 제거한다.


WWDC2019 combine in practice

Apple Developer 내 소개글을 읽어보니, Combine은 비동기 연산 처리를 지원하기 위해 애플에서 새로 내놓은 프레임워크(iOS13+)라는 걸 알 수 있다. 이벤트 처리 연산자를 결합 시켜서 이벤트를 핸들링한다는 내용에서 RxSwift가 생각나는 사람도 있을 것이다. 실제 RxSwift 사용법을 보면, Observable<Element> 인터페이스를 통해 이벤트를 전달(broadcast)하고 전달 받는다. Combine의 publisher와 subscriber 용법과 비슷해보인다.

 

 


RxSwif Usage

 

GitHub - ReactiveX/RxSwift: Reactive Programming in Swift

Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.

github.com

define observable

let searchResults = searchBar.rx.text.orEmpty
    .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
    .distinctUntilChanged()
    .flatMapLatest { query -> Observable<[Repository]> in
        if query.isEmpty {
            return .just([])
        }
        return searchGitHub(query)
            .catchAndReturn([])
    }
    .observe(on: MainScheduler.instance)

binding the results

searchResults
    .bind(to: tableView.rx.items(cellIdentifier: "Cell")) {
        (index, repository: Repository, cell) in
        cell.textLabel?.text = repository.name
        cell.detailTextLabel?.text = repository.url
    }
    .disposed(by: disposeBag)

Combine은 선언식으로 연산자를 호출해서 이벤트를 처리하는 방식을 쓴다. callback이나 completion handler를 작성하는 대신 단일 작업 체인(single processing chain)을 생성한다. 이전 단계에서 받은 element에 Combine의 연산자 추가해서 이전과 다른 추가된 동작을 실행한다. AppleDeveloper내 Combine 소개 페이지에서 실제 사용 예를 보면 실제로 RxSwift와 사용 방식이 비슷하다.

 


 

(대충 이런 내용)TextField에 글자가 입력되거나 변경될 때마다, 데이터를 필터링해서 Table ViewCollection View에 노출하는 화면의 경우를 생각해볼 수 있다. TextField의 keystroke에 Notification을 생성하고, 이를 subscribe(Combine의 subscribe)하면 텍스트가 변경되는 이벤트를 전달 받을 수 있다.

 

Text 변경(textDidChangeNotification)에 해당하는 publish를 생성한다.

let pub = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)

Publisher로 부터 값을 전달 받을때는 Subscriber를 사용한다. 

let sub = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    .sink(receiveCompletion: { print ($0) },
          receiveValue: { print ($0) })

 


메소드명에서 다소 차이는 있지만, RxSwiftCombine은 모두 이벤트를 발행하고 이를 Observing 혹은 Subscribing 하고 있다가 이벤트에 변경이 생기면 반응하는 동일한 방식을 이용하고 있다. Observing(관찰) 과 Subscribing(구독)이라는 말에서 미묘한 차이가 느껴지긴 한다.  

 

Combine을 처음 소개한 WWDC19에서도 Combine을 request-driven 방식이라고 설명했다. 일반 이벤트를 모두에게 알릴 테니, 필요하면 사용하라고 하는 broadcasting방식 사용하는 RxSwift와는 내부적으로 다른 것 같다.

Combine is request-driven, allowing you the opportunity to more carefully manage the memory usage and performance of your app.

WWDC19 : Introducing Combine

 

Introducing Combine - WWDC19 - Videos - Apple Developer

Combine is a unified declarative framework for processing values over time. Learn how it can simplify asynchronous code like networking,...

developer.apple.com

 

  하지만 RxSwiftCombine은 사용방식이나 등장하게 된 이유는 같다. 모두 비동기 이벤트 처리를 단일 체인으로 처리 하기 위해 등장했다. Apple 소개나 문서에서 Reactive라는 단어를 사용하지 않아서 이 글에서도 굳이 사용하지 않았지만 결국 reactive programming개념이 적용된 것이다. RxSwift는 서드파티인 반면 Combine은 네이티브이고, RxSwift는 iOS8부터 사용가능한 반면 Combine은 iOS13부터 사용가능하다. 

 

  iOS 15가 배포된 현재 시점에 생각해보면, Apple은 최소 개발 지원을 두 단계 이전 버전까지로 권고 하고 있기에 minimum target을 iOS13으로 설정 할 수 있다. 그렇다면 굳이 서드파트인 RxSwift를 가져와서 사용하는 것보다는 Combine을 사용하는 게 더 낫다. 기존에 RxSwift를 사용하고 있지 않았더라도, 비동기 이벤트를 처리하려면 이제 Apple이 강력권고(?)하는 Combine을 사용하는 게 좋다. 그러니 여기저기에서 "Combine 적용해야하는데..." 하는 곡소리가 들릴 수 밖에 없었던 것 같다. iOS 개발에서 비동기 이벤트 처리 대세는 Combine이 될 테니 말이다.

 

 

 

반응형