๋‘๋ฒˆ์งธ ๊ธ€์—์„œ๋Š” ์ดํ•ดํ•œ RxSwift์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์„ ๋ฐ”ํƒ•์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์•Œ์•„๋ณธ๋‹ค. ๋ฌด๋ฆฌํ•˜๊ฒŒ ๊ธฐ์–ตํ•  ํ•„์š”๋Š” ์—†๊ณ , ์ด๋ ‡๊ฒŒ ์‚ฌ์ „ ์ œ์ž‘๋œ ํ•จ์ˆ˜๋“ค์ด ๋งŽ๊ณ , ์ž˜ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์œ ์šฉํ•˜๋‹ค๋Š” ์‚ฌ์‹ค๊นŒ์ง€๋งŒ ์ดํ•ดํ•ด๋„ ๋ง›๋ณด๊ธฐ๋กœ๋Š” ์ถฉ๋ถ„ํ•  ๋“ฏ ํ•˜๋‹ค.

๋ณต์Šต

  • ์™œ ์‚ฌ์šฉ?
    • ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํƒ€์ž…์œผ๋กœ ๋ฆฌํ„ดํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•
    • ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ƒ๊ธฐ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜์ค‘์—์ƒ๊ธฐ๋Š”๋ฐ์ดํ„ฐ ํด๋ž˜์Šค ํƒ€์ž…์œผ๋กœ ๊ฐ์‹ธ์„œ ๋งˆ์น˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๋งˆ๋ƒฅ ํƒ€์ž…์œผ๋กœ ๋ฐ›๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ฐฉ๊ฐ์„ ์ฃผ๊ฒŒํ•˜๋Š” ๋ฐฉ๋ฒ•
    • ์‹ค์ œ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•  ๋•Œ ํ•ด๋‹น ๋™์ž‘์ด ๋ฐœ์ƒํ•œ๋‹ค.

Sugar API

  • ๊ทผ๋ฐ ์•ž์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋„ˆ๋ฌด ์‚ฌ์šฉ๋ฒ•์ด ๊ธธ๋‹ค.
  • ๊ท€์ฐฎ์€ ๊ฒƒ์„ ์—†์• ์ฃผ๋Š” API๋ฅผ ์•Œ์•„๋ณด์ž.

๊ทธ๋ƒฅ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ• (Just)

private func downloadJson(url: String) -> Observable<String?> {
        
    Observable.create { emitter in
        emitter.onNext("Hello")
        emitter.onCompleted()
        
        return Disposables.create()
    }
}
private func downloadJson(url: String) -> Observable<String?> {
    return Observable.just("hello")
}
  • ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

์š”์†Œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋ณด๋‚ด๊ณ  ์‹ถ์œผ๋ฉด? (from)

  • ๋งŒ์•ฝ์— ๋‘๊ฐœ๋ฅผ ๋ณด๋‚ด๊ณ  ์‹ถ์œผ๋ฉด?
private func downloadJson(url: String) -> Observable<String?> {
    return Observable.just(["hello", "world"])
}
  • ์ด๋ ‡๊ฒŒ ๋ณด๋‚ด๋ฉด ๊ทผ๋ฐ ๋ฐฐ์—ด ์ž์ฒด๊ฐ€ ๋„˜์–ด๊ฐ€๊ฒŒ ๋จ
private func downloadJson(url: String) -> Observable<String?> {
    return Observable.from(["hello", "world"])
}
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์š”์†Œ ํ•˜๋‚˜์”ฉ onNext๋กœ ๋„˜์–ด๊ฐ„๋‹ค.

onNext๋งŒ ๋ฐ›๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ (subscribe(onNext:))

_ = downloadJson(url: MEMBER_LIST_URL)
    .subscribe { [weak self] event in
        switch event {
        case .next(let json):
            DispatchQueue.main.async { [weak self] in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            }
        case .error(let error):
            print(error)
        case .completed:
            break
        }
    }
  • ์ด๋ ‡๊ฒŒ ๊ณ„์† ์“ฐ๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ๋ถˆํŽธํ•˜๋‹ค.
  • completed ๋œ ๊ฒฝ์šฐ๋‚˜ error์ธ ๊ฒฝ์šฐ ํ•  ๋™์ž‘์ด ์—†๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ์จ๋„ ๋œ๋‹ค.
_ = downloadJson(url: MEMBER_LIST_URL)
    .subscribe(onNext: {
        DispatchQueue.main.async { [weak self] in
            self?.editView.text = json
            self?.setVisibleWithAnimation(self?.activityIndicator, false)
        }
    })
  • ์ด๋ ‡๊ฒŒ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.
  • onComplted, onDisposed ๋“ฑ๋“ฑ์ด ์žˆ๋‹ค.

์ฒ˜๋ฆฌํ•˜๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ• (.observeOn)

@IBAction func onLoad() {
    self.editView.text = ""
    self.setVisibleWithAnimation(self.activityIndicator, true)
    
    _ = downloadJson(url: MEMBER_LIST_URL)
        .subscribe(onNext: { json in
            DispatchQueue.main.async { [weak self] in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            }
        })
    
}
    
  • ๊ธฐ์กด์—๋Š” UIupdate๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, URLSession์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ์—์„œ main ์Šค๋ ˆ๋“œ์—์„œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋„๋ก dispatchQuee๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
@IBAction func onLoad() {
    self.editView.text = ""
    self.setVisibleWithAnimation(self.activityIndicator, true)
    
    _ = downloadJson(url: MEMBER_LIST_URL)
        .observeOn(MainScheduler.instance)
        .subscribe(onNext: { [weak self] json in
            self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
        })
    
}
    
  • ์ด๋ ‡๊ฒŒ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์ž‘์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋ ‡๊ฒŒ subscribe ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ „์— ๋‹ค๋ฅธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•ด์ฃผ๋Š” ๋…€์„๋“ค์„ Operator ๋ผ๊ณ  ํ•œ๋‹ค.
    • map, filter ๋“ฑ๋„ ํ•ด๋‹น๋œ๋‹ค.

Dispose ํ•œ๋ฒˆ์— ํ•˜๊ธฐ (DisposeBag)

  • ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…๋“ค์˜ dispose๋ฅผ ๋ฐฐ์—ด๋กœ ๋“ค๊ณ  ์žˆ๋‹ค๊ฐ€ viewWillDisappear์‹œ์— ๋ชจ๋‘ dispose ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ sugar api๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ,
var disposeBag = DisposeBag()
 
func temp() {
    _ = downloadJson(url: MEMBER_LIST_URL)
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] json in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            })
 
    self.disposeBag.insert(disp)
}
  • ์ด๋ ‡๊ฒŒ ํ•ด๋‘๋ฉด, ํ•ด๋‹น VC์•ˆ์— ์‚ฌ์šฉํ•˜๋Š” ๋ณ€์ˆ˜๋กœ์„œ ๋“ฑ๋ก๋˜๊ธฐ ๋•Œ๋ฌธ์—, VC๊ฐ€ Disappear๋˜๋Š” ์‹œ์ ์— ์ž๋™์œผ๋กœ bag์•ˆ์— ๋‹ด๊ธด ๋ชจ๋“  disposable์ด dispose๋œ๋‹ค.
  • ์ด๊ฒƒ๋„ ์‹ซ๋‹ค!
func temp() {
    _ = downloadJson(url: MEMBER_LIST_URL)
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] json in
                self?.editView.text = json
                self?.setVisibleWithAnimation(self?.activityIndicator, false)
            })
            .disposed(by: self.disposableBag)
}
  • ์ด๋ ‡๊ฒŒ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Marble Diagram ์ฝ๊ธฐ

  • Sugar API๋Š” ๋ฌด์ง€ํ•˜๊ฒŒ ๋งŽ๋‹ค.
  • ํ•จ์ˆ˜์˜ ์ข…๋ฅ˜๊ฐ€ ์—„์ฒญ๋‚˜๊ฒŒ ๋งŽ์€ ๊ฒƒ์ฒ˜๋Ÿผ ์—„์ฒญ ๋งŽ๋‹ค.
  • ์ด๊ฑธ ์™ธ์›Œ์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋‹ˆ, ๋™์ž‘์„ ์ฐพ์•„์„œ ์ ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด ๋•Œ ์„ค๋ช…ํ•˜๋Š” ๋ฐฉ์‹์ด Marble Diagram์ด๋‹ค.
  • ObserveOn ํ•จ์ˆ˜์˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž.

![imAssets/134285034-19761b52-cd5f-40f4-866d-9ad5b2092a0a.png){: .center-small}observeOn

  • ๋จผ์ € ํŒŒ๋ž€์ƒ‰ ์ค„ ์œ„์— ์˜ฌ๋ผ์™€ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋“ค์€ Observable์ด๋‹ค.
  • ํŠน์ • ์—ฐ์‚ฐ์ž๋“ค์€, raw Data๋ฅผ Observable๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ (from) ์ด๊ฒฝ์šฐ๋Š” ํ™”์‚ดํ‘œ์œ„์— ์˜ฌ๋ผ์™€ ์žˆ์ง€ ์•Š๋‹ค.
  • ์•„๋ž˜์˜ ๋ฐ•์Šค๋Š” Operator๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • ์ฒ˜์Œ์„ ๋ณด๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒ€์€์ƒ‰ ํ™”์‚ดํ‘œ๊ฐ€ ์•„๋‹Œ ํŒŒ๋ž€์ƒ‰ ํ™”์‚ดํ‘œ๋กœ ์‹œ์ž‘ํ•œ๋‹ค.
  • ์ด ์ด์œ ๋Š” ์•„๋ž˜์— ๋ณด๋ฉด ๋ณด์ด๋Š” SubscribOn ํ•จ์ˆ˜์˜ ์˜ํ–ฅ์ด๋‹ค.
  • ObserveOn ํ•จ์ˆ˜๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด Observable ๊ฐ์ฒด๋“ค์ด ํ•ด๋‹น operator๊ฐ€ ์ง€์ •ํ•˜๋Š” ์Šค๋ ˆ๋“œ์—์„œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์˜์–ด๋ฅผ ํ•ด์„ํ•ด๋ณด๋ฉด, ์ด๋Ÿฌํ•œ ์Šค๋ ˆ๋“œ์—์„œ ๊ด€์ฐฐ์„ ํ•ด์ค˜ ๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.
  • ์ฆ‰, ๊ด€์ฐฐํ•˜๋Š” ์ชฝ(์˜ˆ๋ฅผ ๋“ค์–ด View) ์—์„œ ์‚ฌ์šฉํ•  ์Šค๋ ˆ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • SubscribOn์˜ ๊ฒฝ์šฐ ์–ด๋Š ์Šค๋ ˆ๋“œ์—์„œ ๊ตฌ๋… ์ž‘์—…์„ ์‹œ์ž‘ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.
  • ๊ทธ๋ž˜์„œ ์–ด๋Š ์‹œ์ ์— ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š”์ง€์— ์ƒ๊ด€์—†์ด ์ฒ˜์Œ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ํŒŒ๋ž€์ƒ‰์ด ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Reference