개요

Combine 프레임워크는 시간 경과에 따라 값을 처리하기 위한 선언적(declarative)인 명령을 제공하는 Swift의 API입니다. 이러한 값은 다양한 종류의 비동기 이벤트(asynchronous event)를 나타낼 수 있습니다.

 

Publisher와 Subscriber

  • Publisher(공표자, 게시자): 시간이 지남에 따라 일련의 값을 전달할 수 있는 타입이라는 것을 선언하는 프로토콜
    • operator: 상류에서 흐르는 퍼블리셔(upstream publisher)로부터 받은 값으로 특정 작업을을 하거나 re-publish 할 수 있도록 함
  • Subscriber(동의자, 구독자): 퍼블리셔의 체인의 끝에서 요소를 받았을 때 작업을 수행할 수 있도록 함
    • 퍼블리셔는 서브스크라이버가 요청했을 때에만 값들을 방출(emit) -> 이벤트 흐름 속도 제어

 

Publisher의 결합(combine) 기능

  • 여러 퍼블리셔들이 출력하는 결과들을 결합하여 앱과 상호작용할 수 있음

 

Combine 채택의 의의

  • 중첩 클로저(nested closure), 콜백을 제거
  • 이벤트 처리 코드의 중앙화
  • 코드를 읽기 쉽고 유지보수가 간편

 

Combine으로 이벤트 수신 및 처리

비동기 소스에서 이벤트를 커스터마이즈 및 수신합니다.

  • 대리자, 완료 핸들러 콜백 대신 이벤트 소스에 대한 단일 체인을 생성

 

예제 1: 텍스트 필드가 있으며 그것을 변경하면 테이블 뷰 또는 컬렉션 뷰의 내용이 실시간으로 변경되어야 하는 앱

Xcode에서 File -> New... -> Playgorund... -> MacOS -> Single App으로 플레이그라운드를 생성한 뒤,

메인 뷰(MyView)에 텍스트 필드(NSTextField)를 추가합니다.

//: A Cocoa based Playground to present user interface

import AppKit
import PlaygroundSupport

class MyViewModel {
    var filterString: String = ""
}

let nibFile = NSNib.Name("MyView")
var topLevelObjects: NSArray?

Bundle.main.loadNibNamed(nibFile, owner:nil, topLevelObjects: &topLevelObjects)
let views = (topLevelObjects as! Array<Any>).filter { $0 is NSView }
let rootView = views[0] as! NSView
let filterField = rootView.subviews[1] as? NSTextField

// Present the view in Playground
PlaygroundPage.current.liveView = rootView
var viewModel = MyViewModel()

// 1. Sink
let pubAndSub = NotificationCenter.default
    // 퍼블리셔 생성
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    // 텍스트값 추출
    .map({ ($0.object as! NSTextField).stringValue })
    // receiveValue: executes when it receives an element from the publisher.
    .sink(receiveCompletion: { print($0) },
          receiveValue: { print($0) })

// 2. Assign
let pubAndSubAssign = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    .map({ ($0.object as! NSTextField).stringValue })
    // 숫자, 알파벳만 필터링
    .filter( { $0.unicodeScalars.allSatisfy({CharacterSet.alphanumerics.contains($0)}) } )
    .map({ "Assgined: " + $0 })
    // Debounce
    .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
    // Specifies the scheduler on which to receive elements from the publisher.
    .receive(on: RunLoop.main)
    // Assigns each element from a publisher to a property on an object.
    .assign(to: \MyViewModel.filterString, on: viewModel)

let assignReceive = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    .sink(receiveValue: { _ in print(viewModel.filterString) })


// // Cancel Publishing when Desired
// sub?.cancel()

 


🚧 이 글은 작성중입니다.

빠른 시일 내에 포스트 작성을 완료하겠습니다.


문의 | 코멘트 또는 yoonbumtae@gmail.com


카테고리: Swift


0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다