2022/01/15 CMC iOS Conference 자료
비동기 프로그래밍을 관찰 가능한 흐름으로 지원해주는 API.
옵저버 패턴과 이터레이터 패턴 그리고 함수형 프로그래밍을 조합한 반응형 프레임워크.
Rx의 심장
Observable = Sequence
T 형태의 데이터 snapshot을 '전달' 할 수 있는 일련의 이벤트를 비동기적으로 생성하는 기능
하나 이상의 observers가 실시간으로 어떤 이벤트에 반응

enum Event<Element> {
case next(Element) // next element of a sequence
case error(Swift.Error) // sequence failed with error
case completed // sequence terminated successfully
}
Finite Observable (단일 스트림 요소 관리)
func download(file: String) -> Observable<Data> {
return Observable<Data>.create { emitter in
let task = URLSession.shared.dataTask(with: URL(string: file)!) { data, _, error in
guard let data = data,
error = nil else {
emitter.onError(error!)
return
}
emitter.onNext(data)
emitter.onCompleted()
}
task.resume()
return Disposables.create { task.cancel() }
}
}
Network.download(file: "<https://www>...")
.subscribeOn(ConcurrentDispatchQueueScheduler.init(queue: DispatchQueue.global()))
.subscribe(onNext: { data in
//임시 파일에 데이터 추가
}, onError: { error in
//사용자에게 에러 표현
}, onCompleted: {
//다운로드 된 파일 사용
})
.disposed(by: disposeBag)
Infinite Observable (무한 스트림 요소 관리)
UIDevice.rx.orientation
.subscribe(onNext: { current in
switch current {
case .landscape:
// 가로모드 배치
case .portrait:
// 세로모드 배치
}
})
.disposed(by: disposeBag)
단일 요소만을 한번 방출
success, error의 이벤트로 구성되어 있음.
Single을 사용하는 일반적인 예는 응답, 오류만 반환할수 있는 HTTP 요청을 수행하는데 사용되지만 단일요소를 사용하여 무한 스트림 요소가 아닌 단일 요소만 관리하는 경우를 모델하는데 사용할수 있음.

func download(file: String) -> Single<Data> {
return Single<Data>.create { single in
let task = URLSession.shared.dataTask(with: URL(string: file)!) { data, _, error in
guard let data = data,
error = nil else {
single(.error(error!)
return
}
single(.success(data))
}
task.resume()
return Disposables.create { task.cancel() }
}
}
Network.download(file: "<https://www>...")
.subscribeOn(ConcurrentDispatchQueueScheduler.init(queue: DispatchQueue.global()))
.subscribe(onSuccess: { json in
//다운로드 된 파일 사용
}, onError: { error in
//사용자에게 에러 표현
})
.disposed(by: disposeBag)
Completable은 완료에 따른 요소에 신경쓰지 않은 경우 사용하면 유용합니다. 요소를 내보낼수 없는 경우 Observable를 사용하여 비교할수 있습니다.
func cacheLocally() -> Completable {
return Completable.create { completable in
// Store some data locally
...
...
guard success else {
completable(.error(CacheError.failedCaching))
return Disposables.create {}
}
completable(.completed)
return Disposables.create {}
}
}
cacheLocally()
.subscribe(onCompleted: {
print("Completed with no error")
}, onError: { error in
print("Completed with an error: \\(error.localizedDescription)")
})
.disposed(by: disposeBag)
RxCocoa란?
다양한 protocol을 extension한 것들과 UIKit을 위한 rx영역을 제공하는 프레임워크
// 기존 방법
Network.fetchName(uid: "dasdjwlqwe")
.subscribeOn(ConcurrentDispatchQueueScheduler.init(queue: DispatchQueue.global()))
.observeOn(MainScheduler.instance) // Main Thread
.catchErrorJustReturn("이름") //next, error, completed, dipose
.materialize()
... // completed, dispose 처리
.dematerialize()
.bind(to: label.rx.text)
.disposed(by: disposeBag)
// asDriver
Network.fetchName(uid: "dasdjwlqwe")
.subscribeOn(ConcurrentDispatchQueueScheduler.init(queue: DispatchQueue.global()))
.asDriver()
.asDriverJustReturn("이름")
.drive(label.rx.text)
.disposed(by: disposeBag)