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)