Traits
Observable이 파생된 형태로 create시 제한적인 이벤트를 사용하고 하고 싶을 때 사용합니다.
간단히 말해 Observable 생성 시
이벤트 onNext, onError, onCompleted를 모두 처리하는 것이 아니라 필요한 이벤트만 사용함.
Traits도 엄연히 Observable이고
Traits을 통해 필요한 이벤트만 사용하여 코드를 조금 더 직관적이고 의도를 명확하게 해 주도록 도와줍니다.
종류
RxSwift에는 Single, Completable, Mabye
RxCocoa는 Driver, Signal
오늘은 RxSwift의 Single, Completable, Mabye만 알아보겠습니다.
Traits의 구현은
각각의 PrimitiveSequence의 create를 통해 Observable을 생성합니다.
설명이 너무 광범위해서... 자세한 내용은 정의를 한번 찾아보세요.
사용방법만 알아봅시다!
public typealias Single<Element> = PrimitiveSequence<SingleTrait, Element>
public typealias Completable = PrimitiveSequence<CompletableTrait, Swift.Never>
public typealias Maybe<Element> = PrimitiveSequence<MaybeTrait, Element>
// 이와같이 Traits은 Observable 타입을 감싸고 있는 Wrapper 구조체입니다.
// PrimitiveSequence == (Trait 타입, 요소)
public struct PrimitiveSequence<Trait, Element> {
let source: Observable<Element>
}
Single
위에서 엄연히 Traits도 Observable이라고 했죠?
마찬가지로 생성 방식도 비슷합니다.
일단 비교를 위해 기존의 Observable을 생성해 보겠습니다.
func observable() -> Observable<Any> {
return Observable.create { observer in
observer.onNext("Operation")
observer.onCompleted()
observer.onError(SomeError.err)
return Disposables.create()
}
}
Single은 오직 성공 및 실패 이벤트만 다룹니다.
func singleObservable() -> Single<Any> {
return Single.create { observer in
observer(.success("Success Operation"))
observer(.failure(SomeError.err))
return Disposables.create()
}
}
success와 failur의 이벤트는 기존의 Observable의 이벤트에서 이와 같은 역할을 같습니다.
.success()
== onNext
+ onCompleted
.failure()
== onError
또한 차이점으로 observer.onNext()
이런 접근이 아닌 observer(.success())
이런식으로 사용되는 이유는
SingleObserver 경우
Traits은 Observable 타입을 감싸고 있는 Wrapper 구조체이기 때문에 실행으로 접근하여
이벤트를 Result로 성공, 실패로 접근하기 때문에 이와 같이 사용합니다.
(아닐수도...)
public typealias SingleEvent<Element> = Result<Element, Swift.Error>
생성을 해줬으니 구독(subscribe)을 해볼까요?
당연히 이벤트도 onSuccess, onFailure, onDisposed 만을 갖고 사용합니다.
singleObservable().subscribe { event in
switch event {
case .success(let data):
print(data)
case .failure(let error):
print(error.localizedDescription)
}
}.dispose()
일반적으로 Single은 성공, 실패로 이벤트를 받을 수 있으므로
API Request에서 주로 사용됩니다.
// 모델
struct ArticleResponse: Codable {
let articles: [Article]
}
struct Article: Codable {
let title: String
}
// Single Observable 생성
func getNews() -> Single<[Article]> {
return Single.create { observer in
let urlString = "https://newsapi.org/v2/everything?q=tesla&sortBy=publishedAt&apiKey=123456789"
AF.request(urlString)
.validate(statusCode: 200...299)
.responseDecodable(of: ArticleResponse.self) { response in
switch response.result {
case .success(let data):
observer(.success(data.articles))
case .failure(let error):
observer(.failure(error))
}
}
return Disposables.create()
}
}
구독(subscribe)
let disposbag = DisposeBag()
// switch문을 통해 이벤트를 호출하거나
getNews()
.subscribe { event in
switch event {
case .success(let data):
debugPrint(data)
case .failure(let error):
print("Failed Request: \(error)")
}
}.disposed(by: disposbag)
// 또는 subscribe(onSuccess:, onError:) 직접 처리
getNews()
.subscribe(
onSuccess: { data in
debugPrint(data)
},
onFailure: { error in
print("Failed Request: \(error)")
})
.disposed(by: disposbag)
Completable
성공 여부만 전달해주고 싶을 때 Completable를 사용합니다.
어떠한 element도 방출하지 않고 순수하게 오류의 발생 또는 성공 여부를 전달하는 목적입니다.
func completableObservable() -> Completable {
return Completable.create { observer in
observer(.completed)
observer(.error(SomeError.err))
return Disposables.create()
}
}
간단한 예제를 살펴봅시다.
만약 스위치가 켜져 있을 때 어떠한 동작을 지정해주고 싶은 경우
var switchOn = true
func checkTheSwitch() -> Completable {
return Completable.create { observer in
// 스위치가 꺼져있으면 오류 발생
guard switchOn else {
observer(.error(SomeError.err))
return Disposables.create()
}
observer(.completed)
return Disposables.create()
}
}
completed를 이벤트 통해 동작을 설정해 줄 수 있습니다.
checkTheSwitch().subscribe { event in
switch event {
case .completed:
print("Completed with no error, Turn off switch")
switchOn = false
print(switchOn)
case .error(let error):
print(error)
}
}.disposed(by: disposbag)
// Completed with no error, Turn off switch
// false
Mabye
Mabye는 Single과 Completable의 중간 특성을 갖고 있는 Observable입니다.
success, completed, error를 모두 배출도 가능하지만
// 1
func mabyeObservable() -> Maybe<Any> {
return Maybe.create { observer in
observer(.success("Mabye Observable"))
observer(.completed)
observer(.error(SomeError.err))
return Disposables.create()
}
}
이와 같이 필요에 따라 생략도 가능합니다.
// 2
func mabyeObservable() -> Maybe<Any> {
return Maybe.create { observer in
observer(.completed)
return Disposables.create()
}
}
mabyeObservable()
.subscribe { event in
switch event {
case.success(let element):
print("Success: \(element)")
case .completed:
print("Complete")
case .error(let error):
print(error)
}
}.disposed(by: disposbag)
// 1
// Mabye Observable
// 2
// Complete
정리 및 참고
Traits의 이벤트 정리
Single : .success()
, .failure()
Completable : .completed
, .error()
Mabye : .success()?
, .completed?
, .error()?
참고
Observable 시퀀스를 as로(Single, Mabye) 변환 시 주의점이 있습니다.
만약 Observable을 asSingle로 변환할 때
Observable의 생성 시 onNext 뒤에는 onCompleted가 와줘야 합니다.
이유는 Single의 success는 onNext + onCompleted이 합쳐진 것이므로
항상 뒤에 같이 써주며 순서를 신경 써줘야 합니다. (아니면 오류 발생)
// 1. 사용 가능
func observable() -> Observable<Any> {
return Observable.create { observer in
observer.onNext("Operation")
observer.onCompleted()
observer.onError(SomeError.err)
return Disposables.create()
}
}
// 2. 오류 발생
func observable() -> Observable<Any> {
return Observable.create { observer in
observer.onNext("Operation")
observer.onError(SomeError.err)
observer.onCompleted()
return Disposables.create()
}
}
구독(subscribe)
observable().asSingle()
.subscribe { event in
switch event {
case .success(let element):
print(element)
case .failure(let error):
print(error)
}
}.disposed(by: disposbag)
// 1
// Operation
// 2
// err
부족한 설명이지만, 조금은 이해 가셨나요?
틀린 내용이 있다면 언제든지 지적해 주시면 감사히 받겠습니다. 🫠
읽어주셔서 감사합니다 😃
'RxSwift' 카테고리의 다른 글
[iOS/RxSwift] Subject의 종류 (0) | 2023.03.09 |
---|---|
[iOS/RxSwift] Hot & Cold Observable (0) | 2023.03.09 |
[iOS/RxSwift] Observable 연산자 (0) | 2023.03.06 |
[iOS/RxSwift] Observable, Subscribe 개념 및 사용 방법 (2) | 2023.03.03 |