[iOS | RxSwift] Traits(Single, Maybe, Completable)

minji0801·2022년 1월 15일
0

RxSwift

목록 보기
3/6
post-thumbnail

개요

Single, Maybe, Completable을 묶어서 Traits(특성)라고 한다.
이 세가지는 지금까지 배운 Observable보다 좁은 범위로 코드 가독성을 높일 수 있다.
그럼 각각 어떤 것인지 알아보자.

Observable에 대해서 잘 모른다면 Observable 어떻게 다루는 걸까..?을 먼저 보고 오는 것을 추천한다.


👀 Traits가 뭐죠..?

Single

success 또는 error 이벤트를 한 번만 방출한다.
여기서 success는 기존의 next 이벤트와 completed 이벤트를 합친 것과 같다.
정확히 한가지 요소만 방출할 수 있다.

Maybe

Single과 비슷하지만 아무런 값을 방출하지 않는 completed 이벤트가 있다.

Completable

completed 또는 error 이벤트만 방출한다.
어떠한 값도 방출하지 않는 Completable은 성공 여부를 확인할 때 유용하게 쓰일 수 있다.


💻 실습하기

Single

Observable과 다르게 subscribe가 onSuccess, onFailure, onDisposed로 구성된다.
여기서 onSuccess는 onNext와 onCompleted를 합친 것이고, onFailure는 onError와 같다.

let disposeBag = DisposeBag()
Single<String>.just("1")
    .subscribe(
        onSuccess: {    // onNext + onCompleted
            print($0)
        }, onFailure: { // onError
            print("error: \($0)")
        }, onDisposed: {
            print("disposed")
        }
    )
    .disposed(by: disposeBag)
// 1
// disposed

Observable에서 asSingle()로 Single을 만들 수도 있다.
이번에는 에러를 발생시켜 보자.

enum TraitsError: Error {
    case single
    case maybe
    case completable
}
Observable<String>.create { observer -> Disposable in
    observer.onError(TraitsError.single)
    return Disposables.create()
}
    .asSingle()
    .subscribe(
        onSuccess: {    // onNext + onCompleted
            print($0)
        }, onFailure: { // onError
            print("error: \($0.localizedDescription)")
        }, onDisposed: {
            print("disposed")
        }
    )
    .disposed(by: disposeBag)
// error: The operation couldn’t be completed. (__lldb_expr_7.TraitsError error 0.)
// disposed

다음과 같이 Decoding 할 때를 예로 들 수 있다.
Single은 반드시 onSuccess 또는 onFailure 이벤트를 방출하기 때문에 정상적으로 디코딩되었는지 확인할 수 있다.

struct SomeJSON: Decodable {
    let name: String
}
enum JSONError: Error {
    case decodingError
}
let json1 = """
            {"name":"alswl"}
            """
let json2 = """
            {"my_name":"ooo"}
            """
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)
// alswl
// decodingError

Maybe

Maybe는 Single와 비슷하지만 completed 이벤트가 있다.

Maybe<String>.just("1")
    .subscribe(
        onSuccess: {
            print($0)
        }, onError: {
            print($0)
        }, onCompleted: {
            print("completed")
        }, onDisposed: {
            print("disposed")
        }
    )
    .disposed(by: disposeBag)
// 1
// disposed

Maybe도 Observable에서 asMaybe()를 통해서 만들 수 있다.
아래 예제는 에러를 발생시킨 것이다.

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")
    }
)
.disposed(by: disposeBag)
// 에러: maybe
// disposed

Completable

Completable은 asSingle(), asMaybe()와 같은 것이 없기 때문에 Completable을 만들고 싶으면 create를 이용해야 한다.
그리고 앞에서 말했듯이 Completable은 completed와 error 이벤트만 방출할 수 있다.

Completable.create { observer -> Disposable in
    observer(.completed)
    return Disposables.create()
}
.subscribe {
    print($0)
}
.disposed(by: disposeBag)
// completed

이번에는 에러를 방출해보자.

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)
// error: completable
// disposed

마무리

이번에는 Traits(Single, Maybe, Completable)에 대해서 알아보았다.
보통 네트워크 통신에서 자주 사용하다고 하는데, 물론 Observable을 사용해도 되지만 좀 더 직관적, 명시적으로 코드를 작성하기 위해서 Traits를 사용하는 것이다.

Observable을 사용할 때 어떤 방식이 제일 효율적인지 고민하며 코드를 작성해야겠다.
다음에는 Subject에 대해서 알아보자!

profile
The genuine iOS Developer

0개의 댓글