Traits 는 모든 경계에서 사용할 수 있는 원시 Observable 을 좀 더 좁은 범위로 제한하여 제공하는데, 인터페이스 경계에서 observable 프로퍼티를 전달하고 보장함으로써 코드에 대한 가독성을 높일 수 있다.
Traits 는 read-only Observable 의 wrapper 형태로 구성되어 있다. 이렇게 Observable에 대한 접근을 제한해놓고 내부에 존재하는 Observable 를 조정하여 일부 기능에 특화된 형태로 사용자에게 제공한다.
struct Single<Element> {
let source: Observable<Element>
...
}
Single
Success 또는 Error 이벤트를 한번만 방출하는 Observable 이다.
이때 success 는 onNext, onCompleted Event 를 합쳐진 것으로, 파일 저장, 파일 다운로드, 디스크에서부터의 데이터 로딩 등 기본적으로 값을 산출하는 비동기적 연산에 사용된다.
e.g. 사진을 저장하는 Observable 이 있다고 했을 때, 저장을 하느냐/에러가 났느냐 와 같이 정확한 한 가지 요소만을 방출하는 연산자를 wrapping 할 때 유용하다.
# 생성 방식
① Single 선언 후, Observable 을 만든다.
Single<String>.just("💚")
.subscribe(
onSuccess: {
print($0)
},
onFailure: {
print("error: \($0)")
},
onDisposed: {
print("disposed")
}
)
.disposed(by: disposeBag)
onSuccess 는 아래의 Observable 로 구현하였을 때의 onNext, onCompleted 두 이벤트가 합쳐진 것이다.
Observable<String>.just("💚")
.subscribe(
onNext: {},
onError: {},
onCompleted: {},
onDisposed: {}
)
② Observable 에 as single 을 붙여서 Single 로 변환할 수 있다.
Observable<String>
.create { observer -> Disposable in
observer.onError(TraitsError.single)
return Disposables.create()
}
.asSingle()
.subscribe(
onSuccess: { print($0) },
onFailure: { print("error: \($0)")},
onDisposed: { print("disposed") }
)
.disposed(by: disposeBag)
다음은 Single 을 활용하여 JSON 을 디코딩하는 함수를 만든 것이다.
struct SomeJSON: Decodable {
let name: String
}
enum JSONError: Error {
case decodingError
}
let json1 = """
{"name":"JUN"}
"""
let json2 = """
{"my_name":"Young"}
"""
func decode(json: String) -> Single<SomeJSON> {
Single<SomeJSON>.create { observer -> Disposable in
guard let data = json.data(using: .utf8),
let json = try? JSONDecoder().decode(SomeJSON.self, from: data)
else {
observer(.failure(JSONError.decodingError))
return Disposables.create()
}
observer(.success(json))
return Disposables.create()
}
}
decode(json: json1)
.subscribe {
switch $0 {
case .success(let json):
print(json.name)
case .failure(let error):
print(error)
}
}
.disposed(by: disposeBag)
decode(json: json2)
.subscribe {
switch $0 {
case .success(let json):
print(json.name)
case .failure(let error):
print(error)
}
}
.disposed(by: disposeBag)
Maybe
성공적으로 Complete 되더라도 아무런 값을 방출하지 않는 형태이다.
Single 과 마찬가지로 Maybe 선언 후, Observable 을 만들거나,
Maybe<String>.just("💚")
.subscribe(
onSuccess: {
print($0)
},
onError: {
print($0)
},
onCompleted: {
print("complete")
},
onDisposed: {
print("disposed")
}
)
.disposed(by: disposeBag)
어떠한 Observable 을 as maybe 를 붙여서 maybe 로 만들 수 있다.
Observable<String>.create { observer -> Disposable in
observer.onError(TraitsError.maybe)
return Disposables.create()
}
.asMaybe()
.subscribe(
onSuccess: {
print("성공 \($0)")
},
onError: {
print("에러 \($0)")
},
onCompleted: {
print("complete")
},
onDisposed: {
print("disposed")
}
)
.disposed(by: disposeBag)
Completable
Completable 은 아무런 값을 방출하지 않고, Completed or Error 만을 방출한다. Completable 은 동기식 연산의 성공 여부를 확인할 때 유용하게 사용된다.
그렇다면 Single, Maybe 와 같이 Observable 에 asCompletable 을 붙이는 것만으로도 바꿀 수 있을까? NO
왜냐하면 Observable 은 값 요소를 방출할 수 있지만, Completable 은 completed, error 만을 방출하기 때문에 값 요소를 방출한 이상 이를 completable 로 변환할 수 없다.
만약 completable sequence 를 생성하고 싶다면, completable create 통해 생성할 수 있다.
Completable.create { observer -> Disposable in
observer(.error(TraitsError.completable))
return Disposables.create()
}
.subscribe(
onCompleted: {
print("completed!!!!")
},
onError: {
print("error: \($0)")
},
onDisposed: {
print("disposed")
}
)
.disposed(by: disposeBag)
' iOS > RxSwift' 카테고리의 다른 글
RxSwift - Filter (1) | 2022.11.01 |
---|---|
RxSwift - Subject (0) | 2022.11.01 |
RxSwift - Observable 과 dispose / disposeBag (0) | 2022.10.24 |
RxSwift - Observable 과 subscribe (0) | 2022.10.24 |
RxSwift - Observable 생성 시 사용하는 연산자 정리 (0) | 2022.10.24 |