Single, Maybe, Completable은 다른 옵저버블보다 좁은 범위의 옵저버블이다.
선택적으로 사용할 수 있는데, 이런 좁은범위의 옵저버블을 사용하는 이유는 코드 가독성을 높이는데 있다.
Single
Single은 두가지 이벤트만 방출한다.
- .success(): next event와 complete 를 합친것과 같다. 값을 포함해서 방출한다.
- .error()
파일 저장이나 다운로드, 디스크에서 데이터 로딩과 같이 기본적으로 값을 산출하는 비동기적 연산에 사용되게된다.
사진을 저장하는 옵저버블이 있을 때 저장을 했느냐, 에러가 났느냐 처럼 정확히 한가지 요소만을 방출하는 연산자를 매핑할 때 유용하다.
정확히 한가지 요소만을 방출할 수 있다.
NextEvent와 Completed Event를 합친 Success를 방출하고 종료된다.
또는 에러를 방출시키고 종료된다.
Single<>로 Single을 생성하거나, 일반옵저버블을 asSingle로 변형할 수 있다.
Single<String>.just("✅")
.subscribe(onSuccess: {
print($0)
}, onFailure: {
print("error: \($0)")
}, onDisposed: {
print("disposed")
})
.disposed(by: disposeBag)
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 SomeData: Decodable{
let name: String
}
enum ParsingError: Error{
case decodingError
}
let json1 = """
{"name":"GO"}
"""
let json2 = """
{"myname":"GOGO"}
"""
func decode(json: String) -> Single<SomeData>{
Single<SomeData>.create { observer -> Disposable in
guard let data = json.data(using: .utf8),
let json = try? JSONDecoder().decode(SomeData.self, from: data) else{
observer(.failure(ParsingError.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)
// 에러 json의 차이
decode(json: json2)
.subscribe{
switch $0{
case .success(let json):
print(json.name)
case .failure(let error):
print(error)
}
}
.disposed(by: disposeBag)
Maybe
Single과 비슷하지만 유일하게 다른점은 completed되더라도 아무런 값을 방출하지 않는 complete를 포함한다.
- .success(): next event와 complete 를 합친것과 같다. 값을 포함해서 방출한다.
- .completed: 아무런 값을 방출하지 않는다
- .error()
사진을 가지고 있는 커스텀포토앨범앱이 있을 경우 거기서 만든 앨범 이름은 유저디폴트에 저장될거고, 해당 id로 앨범을 열고, 사진을 저장할 때 마다 기록이 남는다.
Maybe 메서드를 통해 상황을 관리할 수 있다.
1. 만약 id가 여전히 존재할경우 -> .completed
2. 유저가 앨범을 삭제하거나 새로운 앨범을 생성할 경우 -> .success(id) success에 id를 담아서 방출할 수 있다.
3. 사진을 가져오거나 삭제하는 과정에서 잘못된경우 -> .error(에러)
Maybe<>로 Maybe을 생성하거나, 일반옵저버블을 asMaybe로 변형할 수 있다.
Maybe<String>.just("✅")
.subscribe(onSuccess: {
print($0)
}, onError: {
print($0)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
.disposed(by: disposeBag)
Observable<String>.create{ observer -> Disposable in
observer.onError(TraitsError.maybe)
return Disposables.create()
}
.asMaybe()
.subscribe(onSuccess: {
print($0)
}, onError: {
print($0)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
Completable
completed, error만을 방출한다. 어떤 값도 방출하지 않는다.
- .completed: 값을 포함하지 않는다.
- .error()
asCompletable같은건 존재하지 않는다. 옵저버블을 Completable로 변경할 순 없다.
옵저버블은 값을 방출할 수 있지만 Completabel은 completed, error만 방출할 수 있기 때문이다.
값을 방출한 이상 Completable이 될 순 없다.
Completable.crate()를 통해서만 생성할 수 있다.
유저가 작업할 동안 데이터가 자동으로 저장되는 기능을 만들고 싶다고 할 경우 백그라운드큐에서 비동기적으로 저장한 다음에 완료가 되면 노티를 띄우거나 저장중 오류가 생기면 알럿을 띄우고 싶을 것이다. 이런 경우 작업이 완료되었는지, 안되었는지만 알면 되기 때문에 어떤 값이 필요가 없다. 다만 에러가 발생할 경우 어떤 에러가 발생헀는지는 알려야한다 이럴경우 Completable이 유용하다.
Completable.create { observer -> Disposable in
// completed, error 두개밖에 없다.
observer(.error(TraitsError.completable))
return Disposables.create()
}
.subscribe(onCompleted: {
print("completed")
}, onError: {
print("eroror: \($0)")
}, onDisposed: {
print("disposed")
})
.disposed(by: disposeBag)