๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐ŸŽ iOS/RxSwift

[RxSwift] Traits - Single, Completable, Maybe

์•ˆ๋…•ํ•˜์„ธ์š” ์ œ์ธ์ž…๋‹ˆ๋‹ค!

์˜ค๋Š˜์€ Traits๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ , RxSwift์˜ Traits์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

(RxCocoa์˜ Traits๋Š” ๋‹ค์Œ ๊ฒŒ์‹œ๊ธ€์—์„œ ์ด์–ด์„œ ์ •๋ฆฌํ•˜๋„๋ก ํ• ๊ฒŒ์š”!)

์ด๋ฒˆ ๊ฒŒ์‹œ๊ธ€์€ ReactiveX/RxSwift์˜ Traits ๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ•˜๋ฉด์„œ Traits์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Traits๋ž€?

Swift๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ •ํ™•์„ฑ๊ณผ ์•ˆ์ •์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ณ  Rx ์‚ฌ์šฉ์„ ๋ณด๋‹ค ์ง๊ด€์ ์ด๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ์œ ํ˜• ์‹œ์Šคํ…œ์„ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Traits๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ์‹œํ€€์Šค ์†์„ฑ์„ ์ „๋‹ฌํ•˜๊ณ  ๋ณด์žฅํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“  ์ปจํ…์ŠคํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์›์‹œ Observable๊ณผ ๋น„๊ตํ•  ๋•Œ ๋ฌธ๋งฅ์ ์ธ ์˜๋ฏธ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๋” ๊ตฌ์ฒด์ ์ธ use-cases๋ฅผ ํƒ€๊ฒŸ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

Traits์˜ ์‚ฌ์šฉ์€ ์„ ํƒ์‚ฌํ•ญ์ด๋ฉฐ, ์‚ฌ์šฉ ๋ชฉ์ ์€ ์ฝ”๋“œ๋ฅผ ์ฝ๋Š” ์‚ฌ๋žŒ์—๊ฒŒ ์˜๋„๋ฅผ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. Traits๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ์ง๊ด€์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

Traits์€ ์ฝ๊ธฐ์ „์šฉ(read-only) Observable sequence property์„ ๋žฉํ•‘ํ•˜๋Š” ๊ตฌ์กฐ์ฒด ์ž…๋‹ˆ๋‹ค.

 

struct Single<Element> {
    let source: Observable<Element>
}

struct Driver<Element> {
    let source: Observable<Element>
}
...

 

observable sequence์— ๋Œ€ํ•œ ์ผ์ข…์˜ ๋นŒ๋” ํŒจํ„ด ๊ตฌํ˜„์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Traits ์ƒ์„ฑ ํ›„, .asObservable()์„ ํ˜ธ์ถœํ•˜๋ฉด ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ ํ‰๋ฒ”ํ•œ observable sequence๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

RxSwift Traits์˜ ์ข…๋ฅ˜

RxSwift์˜ Traits๋กœ๋Š” Single, Completable, Maybe๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

Single

Single์€ ์ผ๋ จ์˜ ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•˜๋Š” ๋Œ€์‹  ํ•ญ์ƒ ๋‹จ์ผ ์š”์†Œ ๋˜๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ถœํ•˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๋Š” Observable์˜ ๋ณ€ํ˜•์ž…๋‹ˆ๋‹ค .

 

  • ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ ์š”์†Œ ๋˜๋Š” error๋ฅผ ๋ฐฉ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • ๋ถ€์ˆ˜์ž‘์šฉ์„ ๊ณต์œ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Single์„ ์‚ฌ์šฉํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€ ์ค‘ ํ•˜๋‚˜๋Š” ์‘๋‹ต์ด๋‚˜ ์˜ค๋ฅ˜๋งŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” HTTP ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, Single์€ ๋ฌดํ•œํ•œ ์ŠคํŠธ๋ฆผ ์š”์†Œ๊ฐ€ ์•„๋‹Œ ๋‹จ์ผ ์š”์†Œ๋งŒ ๊ณ ๋ คํ•˜๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Single ์ƒ์„ฑํ•˜๊ธฐ

Single์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ Observable์„ ๋งŒ๋“œ๋Š”๊ฒƒ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ด…์‹œ๋‹ค.

func getRepo(_ repo: String) -> Single<[String: Any]> {
    return Single<[String: Any]>.create { single in
        let task = URLSession.shared.dataTask(with: URL(string: "https://api.github.com/repos/\(repo)")!) { data, _, error in
            if let error = error {
                single(.failure(error))
                return
            }

            guard let data = data,
                  let json = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves),
                  let result = json as? [String: Any] else {
                single(.failure(DataError.cantParseJSON))
                return
            }

            single(.success(result))
        }

        task.resume()

        return Disposables.create { task.cancel() }
    }
}

์œ„์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (HTTP ์š”์ฒญ ์„ฑ๊ณต, ์‹คํŒจ์— ๋”ฐ๋ฅธ ์ฒ˜๋ฆฌ)

getRepo("ReactiveX/RxSwift")
    .subscribe { event in
        switch event {
            case .success(let json):
                print("JSON: ", json)
            case .failure(let error):
                print("Error: ", error)
        }
    }
    .disposed(by: disposeBag)

ํ˜น์€ subscribe(onSuccess:onError:) ๋ฅผ ์ด์šฉํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

getRepo("ReactiveX/RxSwift")
    .subscribe(onSuccess: { json in
                   print("JSON: ", json)
               },
               onError: { error in
                   print("Error: ", error)
               })
    .disposed(by: disposeBag)

subscription์€ Single์˜ ํƒ€์ž… ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๋Š” .success, .error์ผ ์ˆ˜ ์žˆ๋Š” Swift์˜ Result ์—ด๊ฑฐํ˜•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฒซ๋ฒˆ์งธ ์ด๋ฒคํŠธ ์ดํ›„์—๋Š” ๋” ์ด์ƒ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// RxSwift > Single.swift
public typealias SingleEvent<Element> = Result<Element, Swift.Error>

public func subscribe(_ observer: @escaping (SingleEvent<Element>) -> Void) -> Disposable {
        var stopped = false
        return self.primitiveSequence.asObservable().subscribe { event in
            if stopped { return }
            stopped = true
            
            switch event {
            case .next(let element):
                observer(.success(element))
            case .error(let error):
                observer(.failure(error))
            case .completed:
                rxFatalErrorInDebug("Singles can't emit a completion event")
            }
        }
    }

๋˜ํ•œ, ์›๋ณธ Observable sequence์— .asSingle()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Single๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Completable

Completable์€ ์˜ค์ง complete ํ˜น์€ error๋งŒ ๋ฐฉ์ถœํ•  ์ˆ˜ ์žˆ๋Š” Observable์˜ ๋ณ€ํ˜•์œผ๋กœ, ์–ด๋– ํ•œ ์š”์†Œ๋„ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

 

  • ์ œ๋กœ ์š”์†Œ ๋ฐฉ์ถœ
  • ์™„๋ฃŒ ์ด๋ฒคํŠธ ๋˜๋Š” ์—๋Ÿฌ ๋ฐฉ์ถœ
  • ๋ถ€์ˆ˜์ž‘์šฉ์„ ๊ณต์œ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Completable์€ ์ž‘์—…์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ์‚ฌ์‹ค์—๋งŒ ๊ด€์‹ฌ์žˆ๊ณ  ์™„๋ฃŒ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ์š”์†Œ์—๋Š” ๊ด€์‹ฌ์ด ์—†๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Observable<Void>๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์š”์†Œ๋“ค์„ ๋ฐฉ์ถœํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์™€ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Completable ์ƒ์„ฑํ•˜๊ธฐ

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 { completable in
        switch completable {
            case .completed:
                print("Completed with no error")
            case .error(let error):
                print("Completed with an error: \(error.localizedDescription)")
        }
    }
    .disposed(by: disposeBag)

๋˜๋Š” subscribe(onCompleted:onError:)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

cacheLocally()
    .subscribe(onCompleted: {
                   print("Completed with no error")
               },
               onError: { error in
                   print("Completed with an error: \(error.localizedDescription)")
               })
    .disposed(by: disposeBag)

๊ตฌ๋…์€ ์ž‘์—…์ด ์˜ค๋ฅ˜ ์—†์ด ์™„๋ฃŒ๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” .completed  ๋˜๋Š” .error์ผ ์ˆ˜ ์žˆ๋Š” CompletableEvent ์—ด๊ฑฐํ˜•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์ด๋ฒคํŠธ ์ดํ›„์—๋Š” ๋” ์ด์ƒ์˜ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Maybe

Maybe๋Š” Single๊ณผ Completable ์‚ฌ์ด์— ์žˆ๋Š” Observable์˜ ๋ณ€ํ˜•์ž…๋‹ˆ๋‹ค. ๋‹จ์ผ ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•˜๊ฑฐ๋‚˜, ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๊ณ  ์™„๋ฃŒํ•˜๊ฑฐ๋‚˜, ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Note: ์ด ์„ธ ๊ฐ€์ง€ ์ด๋ฒคํŠธ๋Š” Maybe๋ฅผ ์ข…๋ฃŒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ฆ‰, ์ข…๋ฃŒ๋œ Maybe๋Š” ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•  ์ˆ˜ ์—†๊ณ  ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•œ Maybe ์—ญ์‹œ ์ข…๋ฃŒ ์ด๋ฒคํŠธ๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (= ์„ธ ๊ฐ€์ง€ ์ด๋ฒคํŠธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐฉ์ถœ๋˜๋ฉด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค)

 

  • ์™„๋ฃŒ๋œ ์ด๋ฒคํŠธ, ์‹ฑ๊ธ€์ด๋ฒคํŠธ ๋˜๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • ๋ถ€์ˆ˜์ž‘์šฉ์„ ๊ณต์œ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Maybe๋Š” ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋–ค ์ž‘์—…์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ์š”์†Œ๋ฅผ ๋ฐ˜๋“œ์‹œ ๋ฐฉ์ถœํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

Maybe ์ƒ์„ฑํ•˜๊ธฐ

Maybe๋Š” Observabled์„ ๋งŒ๋“œ๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

func generateString() -> Maybe<String> {
    return Maybe<String>.create { maybe in
        maybe(.success("RxSwift"))

        // OR

        maybe(.completed)

        // OR

        maybe(.error(error))

        return Disposables.create {}
    }
}

์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

generateString()
    .subscribe { maybe in
        switch maybe {
            case .success(let element):
                print("Completed with element \(element)")
            case .completed:
                print("Completed with no element")
            case .error(let error):
                print("Completed with an error \(error.localizedDescription)")
        }
    }
    .disposed(by: disposeBag)

ํ˜น์€ subscribe(onSuccess:onError:onCompleted:)์„ ์ด์šฉํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

generateString()
    .subscribe(onSuccess: { element in
                   print("Completed with element \(element)")
               },
               onError: { error in
                   print("Completed with an error \(error.localizedDescription)")
               },
               onCompleted: {
                   print("Completed with no element")
               })
    .disposed(by: disposeBag)

.asMaybe()๋ฅผ ์‚ฌ์šฉํ•ด ์›์‹œ Observable ์‹œํ€€์Šค๋ฅผ Maybe๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ ๋˜ํ•œ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ •๋ฆฌ

RxSwift์˜ Traits ์„ธ ๊ฐ€์ง€์— ๋Œ€ํ•ด ReactiveX ๊นƒํ—ˆ๋ธŒ ๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ•˜๋ฉด์„œ ์•Œ์•„๋ณด์•˜๋Š”๋ฐ์š”, ์ œ๊ฐ€ ์ดํ•ดํ•œ๋Œ€๋กœ ์ •๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

Traits์€ 'ํŠน์„ฑ'์ด๋ผ๊ณ  ์ง์—ญํ•  ์ˆ˜ ์žˆ๋“ฏ์ด ์–ด๋–ค ํŠน์„ฑ์ด ์กด์žฌํ•˜๋Š” Observable ์‹œํ€€์Šค์ž…๋‹ˆ๋‹ค.

Traits์€ read-only Observable์˜ wrapper ํ˜•ํƒœ๋กœ,  Observable์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œํ•œํ•ด์„œ ๋‚ด๋ถ€์— ์กด์žฌํ•˜๋Š” Observable์„ ์กฐ์ •ํ•˜์—ฌ ์ผ๋ถ€ ๊ธฐ๋Šฅ์— ํŠนํ™”๋œ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Traits์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ๋ช…ํ™•ํ•˜๊ณ  ์ง๊ด€์ ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

1. Single

- ํ•ญ์ƒ ๋‹จ์ผ ์š”์†Œ ๋˜๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ถœ

-> ์„ฑ๊ณต ์‹œ ๋‹จ์ผ ์š”์†Œ ๋ฐฉ์ถœ, ์‹คํŒจ ์‹œ error๋ฅผ ๋ฐฉ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ๋””์Šคํฌ์—์„œ ๋กœ๋“œํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ์„ฑ๊ณต or ์‹คํŒจ์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ผํšŒ์„ฑ ํ”„๋กœ์„ธ์Šค์— ์œ ์šฉ

 

2. Completable

- ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๊ณ , ์˜ค์ง complete ํ˜น์€ error๋งŒ ๋ฐฉ์ถœ

-> ์ž‘์—…์˜ ์„ฑ๊ณต, ์‹คํŒจ ์—ฌ๋ถ€๋งŒ์„ ํŒ๋‹จํ•˜๋Š” ๊ฒฝ์šฐ ์œ ์šฉ

 

3. Maybe

- ๋‹จ์ผ ์š”์†Œ๋ฅผ ๋ฐฉ์ถœ or ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๊ณ  ์™„๋ฃŒ or ์˜ค๋ฅ˜ ๋ฐฉ์ถœ (์„ธ ๊ฐ€์ง€ ์ค‘ ํ•˜๋‚˜ ๋ฐฉ์ถœํ•˜๊ณ  ์ข…๋ฃŒ๋จ)

-> ์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์—์„œ ์„ฑ๊ณต ์‹œ ์„ ํƒ์ ์œผ๋กœ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์œ ์šฉ

'๐ŸŽ iOS > RxSwift' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[RxSwift] Traits - Driver, Signal, Control Property/ControlEvent  (0) 2023.04.29
[RxSwift] Relay๋ž€?  (0) 2023.02.17
[RxSwift] Subject๋ž€?  (0) 2023.02.03
[RxSwift] Observable  (0) 2022.05.02
[RxSwift] RxSwift์™€ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ  (7) 2022.04.07