λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🍎 iOS/RxSwift

[iOS] MVVM & RxSwift μŠ€ν„°λ”” W1 - Observable 생λͺ…주기와 μ“°λ ˆλ“œκ΄€λ¦¬

by Danna 2021. 7. 11.
728x90
728x90
 

iamchiwon/RxSwift_In_4_Hours

RxSwift, 4μ‹œκ°„ μ•ˆμ— λΉ λ₯΄κ²Œ μ΅ν˜€ 싀무에 μ‚¬μš©ν•˜κΈ°. Contribute to iamchiwon/RxSwift_In_4_Hours development by creating an account on GitHub.

github.com

κ³°νŠ€κΉ€λ‹˜ κ°•μ˜ μ˜μƒμ„ 보고, μ •λ¦¬ν•œ λ‚΄μš©μž…λ‹ˆλ‹€!

 

[1κ΅μ‹œ] RxSwift λ₯Ό μ΄μš©ν•œ 비동기 ν”„λ‘œκ·Έλž˜λ°

πŸ’‘ RxSwift λŠ” 비동기 μž‘μ—…μ˜ κ²°κ³Όλ₯Ό Completion closure κ°€ μ•„λ‹Œ, ν•¨μˆ˜μ˜ return κ°’μœΌλ‘œ μ „λ‹¬ν•˜κΈ° μœ„ν•œ μœ ν‹Έλ¦¬ν‹° 쀑 ν•˜λ‚˜μ΄λ‹€!

 

πŸ‘€ 비동기 ν”„λ‘œκ·Έλž˜λ°, RxSwift κ°€ μ™œ ν•„μš”ν• κΉŒ? 

 

λ„€νŠΈμ›Œν¬ μž‘μ—… λ“± 데이터λ₯Ό λ°›μ•„μ˜€λŠ” 데 μ‹œκ°„μ΄ κ±Έλ¦¬λŠ” μž‘μ—…μ˜ 경우, 비동기 ν”„λ‘œκ·Έλž˜λ°μ΄ ν•„μš”ν•˜λ‹€.

동기(sync)둜 μ§„ν–‰λœλ‹€λ©΄, 데이터λ₯Ό λ°›μ•„μ˜€λŠ” λ™μ•ˆ λ‹€λ₯Έ UI μž‘μ—…μ΄ 진행될 수 μ—†κ²Œλœλ‹€.

κΈ°μ‘΄ 비동기(async) ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” 데이터가 받아지면, completion closure 둜 전달해 μ΄μš©ν–ˆλ‹€.

근데, closure κ°€ μ—¬λŸ¬κ°œκ°€ μ€‘μ²©λ˜κ²Œ 되면 μ½”λ“œμ˜ 가독성이 떨어지고, μ—λŸ¬ μ²˜λ¦¬κ°€ μ–΄λ ΅κ²Œ λœλ‹€.

 

이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄, closure 둜 μ „λ‹¬ν•˜λŠ” 게 μ•„λ‹Œ, ν•¨μˆ˜μ˜ λ¦¬ν„΄κ°’μœΌλ‘œ 데이터λ₯Ό μ „λ‹¬ν•˜κΈ° μœ„ν•œ 방법이 μžˆλ‹€!

"λ‚˜μ€‘μ— μƒκΈ°λŠ” 데이터" νƒ€μž…, didSet 을 μ΄μš©ν•΄ 데이터가 섀정됐을 λ•Œ μ²˜λ¦¬ν•  closureλ₯Ό μ§€μ •ν•œ ν›„, 비동기 μž‘μ—…μ˜ μ™„λ£Œκ°’μœΌλ‘œ "λ‚˜μ€‘μ— μƒκΈ°λŠ” 데이터" μΈμŠ€ν„΄μŠ€λ₯Ό μ „λ‹¬ν•œλ‹€.

πŸ‘‰ RxSwift μ—μ„œλŠ” "λ‚˜μ€‘μ— μƒκΈ°λŠ” 데이터" νƒ€μž…μ˜ 이름을 Observable 이라고 λΆ€λ₯΄λ©°, 데이터 값이 λ³€ν• λ•Œ μˆ˜ν–‰ν•  closureλ₯Ό subscribe μ˜€νΌλ ˆμ΄ν„°λ₯Ό 톡해 지정할 수 μžˆλ‹€.

 

 

βœ”οΈŽ RxSwift λ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ•„λž˜ 두 가지 방법을 μ•Œλ©΄ λœλ‹€.

 

1. λΉ„λ™κΈ°λ‘œ μƒκΈ°λŠ” 데이터λ₯Ό Observable 둜 κ°μ‹Έμ„œ λ¦¬ν„΄ν•˜λŠ” 방법

2. Observable 둜 μ˜€λŠ” 데이터λ₯Ό λ°›μ•„μ„œ μ²˜λ¦¬ν•˜λŠ” 방법


 

1. λΉ„λ™κΈ°λ‘œ μƒκΈ°λŠ” 데이터λ₯Ό Observable 둜 κ°μ‹Έμ„œ λ¦¬ν„΄ν•˜λŠ” 방법

  • κΈ°λ³Έ μ‚¬μš©λ²• :: Observable 을 create ν•œ ν›„, 전달할 데이터λ₯Ό onNext(data) λ₯Ό 톡해 μ „λ‹¬ν•˜κ³  onCompleted() λ₯Ό 톡해 μ’…λ£Œν•œλ‹€. Error μ²˜λ¦¬κ°€ ν•„μš”ν•˜λ‹€λ©΄ onError(error) λ₯Ό 톡해 μ „λ‹¬ν•œλ‹€.
  • 데이터가 ν•˜λ‚˜λΌλ©΄, just ν•œ μ€„λ‘œ μž‘μ„±ν•˜μž! 
  • 데이터가 μ—¬λŸ¬κ°œλΌλ©΄, from μ˜€νΌλ ˆμ΄ν„°λ₯Ό μ΄μš©ν•˜μž!
  • μ—¬κΈ°μ„œ just, from 같은 operator λ₯Ό Sugar API 라고 λΆ€λ₯Έλ‹€κ³  ν•œλ‹€. (λ‹¬μ½€ν•œ.. μ‚¬μš©λ²• ?😁) 
// 1 κΈ°λ³Έ μ‚¬μš©λ²•
func downloadJson(_ url: String) -> Observable<String?> {
    return Observable.create { emitter in
        emitter.onNext(data)
        emitter.onCompleted()
        return Disposables.create()
    }
}

// 2 Just !
func downloadJson(_ url: String) -> Observable<String?> {
    return Observable.just(data)
}

// 3 from ! 
func downloadJson(_ url: String) -> Observable<String?> {
    return Observable.from([data1, data2])
}

 

2. Observable 둜 μ˜€λŠ” 데이터λ₯Ό λ°›μ•„μ„œ μ²˜λ¦¬ν•˜λŠ” 방법

  • κΈ°λ³Έ μ‚¬μš©λ²• :: observables.subscirbe { event in ... } λ©”μ†Œλ“œλ₯Ό 톡해 데이터λ₯Ό λ°›μ•„μ˜¬ 수 μžˆλ‹€. closure μ—μ„œ event λ₯Ό λ°›μ•„μ˜¬ 수 μžˆλŠ”λ°, μ΄λŠ” next, error, completed 둜 κ΅¬λΆ„λœλ‹€. switch - case ꡬ문을 μ΄μš©ν•΄ 각각 ν•„μš”ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•œλ‹€.
  • μΆ”κ°€μ μœΌλ‘œ, subscribe 호좜의 κ²°κ³Όκ°’μœΌλ‘œλŠ” disposable 이 λ¦¬ν„΄λœλ‹€. μ΄λŠ” ν•„μš”μ— 따라 dispose() ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄ νƒœμŠ€ν¬λ₯Ό μ·¨μ†Œν•  수 μžˆλ‹€. μ·¨μ†Œκ°€ ν•„μš” μ—†λŠ” 경우, λ°˜ν™˜κ°’μ„ _ 으둜 μ „λ‹¬λ°›μœΌλ©΄ κ²½κ³ λ₯Ό 없앨 수 μžˆλ‹€.
  • subscribe μ—μ„œ μ²˜λ¦¬ν•˜κ³  싢은 event 만 ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜ ν˜•νƒœλ‘œ μž‘μ„±ν•  수 μžˆλ‹€.
// 1 κΈ°λ³Έ μ‚¬μš©λ²•
_ = downloadJson(MEMBER_LIST_URL)
    .subscribe { event in
        switch event {
        case .next(let json):
            // main queue μ—μ„œ UI μž‘μ—… λ“±
        case .completed:
            break
        case .error:
            break
        }
    }
    
// 2 λ§€κ°œλ³€μˆ˜ ν˜•νƒœλ‘œ μ‚¬μš©λ²• (Sugar API?)
_ = downloadJson(MEMBER_LIST_URL)
		.subscribe(onNext: { ... })

λ§€κ°œλ³€μˆ˜κ°€ μžˆλŠ” subscribe ν•¨μˆ˜ μ •μ˜

 

3. Operator, Sugar API ?? 🀨

  • 기본적인 μ‚¬μš©λ²•μ„ 짧게, κ°„λ‹¨ν•˜κ²Œ μ‚¬μš©ν•˜κΈ° μœ„ν•œ Sugar API λ₯Ό μ œκ³΅ν•˜λŠ”λ°, 이λ₯Ό operator 라고 ν•œλ‹€.
  • create, subscribe, 데이터 μ‘°μž‘(map, filter) λͺ¨λ‘ operator 라고 ν•œλ‹€.
  • reactivex.io μ—μ„œ operator 의 λ§ˆλΈ” λ‹€μ΄μ–΄κ·Έλž¨μ„ μ‚΄νŽ΄λ³Ό 수 μžˆλ‹€.  (λ§ˆλΈ” λ‹€μ΄μ–΄κ·Έλž¨μ€ Observable κ³Ό 이λ₯Ό κ΅¬λ…ν•˜λŠ” subscribe μ—μ„œ μ–΄λ–»κ²Œ 데이터가 μ „λ‹¬λ˜λŠ”μ§€λ₯Ό 확인해볼 수 μžˆλŠ” λ‹€μ΄μ–΄κ·Έλž¨μ΄λ‹€.)

 

πŸ‘€ operator μ‚΄νŽ΄λ³΄κΈ° 

 

  • μœ„μ—μ„œ μ‚΄νŽ΄λ³Έ just, from 은 생성(create) 에 κ΄€λ ¨λœ operator 이닀.
  • observable 의 값이 λ³€ν•œ ν›„ 데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” subscribe μ—μ„œ main queue block 을 λ§Œλ“œλŠ”κ²ƒ λŒ€μ‹  .observe(on: MainScheduler.instance) 등을 μ‚¬μš©ν•΄ μ“°λ ˆλ“œλ₯Ό μ§€μ •ν•˜λŠ” operator 도 μžˆλ‹€.
  • 데이터가 Subscribe 둜 μ „λ‹¬λ˜κΈ° 전에 map, filter ν•¨μˆ˜ 등을 μ΄μš©ν•  수 μžˆλ‹€. κΈ°μ‘΄ Swift μ—μ„œ μ΄μš©ν•˜λ˜ ν•¨μˆ˜ λ™μž‘κ³Ό κ°™λ‹€.

[2κ΅μ‹œ] Observable 생λͺ…μ£ΌκΈ°, μ“°λ ˆλ“œ 관리

🌱 Observable 의 생λͺ…μ£ΌκΈ°

1. Create
2. Subscribed
3. Next (μˆ˜ν–‰)
- - - 끝 - - -
4. Completed / Error
5. Disposabled

 

참고사항

 

  • Observable 을 λ§Œλ“€μ–΄λ‘”λ‹€κ³  해도 μ‹€ν–‰λ˜μ§€ μ•ŠμŒ. subscribe ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄μ•Όλ§Œ μ „λ‹¬λœλ‹€.
  • Observable 은 Completed, Error λ“±μœΌλ‘œ λλ‚œ ν›„ μž¬μ‚¬μš©ν•  수 μ—†λ‹€. dispose λ“± λλ‚œ ν›„ subscribe ν•¨μˆ˜λ₯Ό λ‹€μ‹œ ν˜ΈμΆœν•΄μ•Όλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.
  • Complted or Error 둜 λλ‚˜λ„ Disposabled 둜 κ°€κ³ , 쀑간에 μ·¨μ†Œν•˜λ”λΌλ„ Disposabled 둜 κ°„λ‹€.

 

πŸ€” μˆœν™˜μ°Έμ‘°μ™€ λ©”λͺ¨λ¦¬ 관리

πŸ’‘ μˆœν™˜ μ°Έμ‘°?! λ‘ 개의 클래슀 μΈμŠ€ν„΄μŠ€λ“€μ΄ κ°•ν•œμ°Έμ‘°λ‘œ μ„œλ‘œλ₯Ό λΆ™μž‘κ³  μžˆμ–΄, 레퍼런슀 μΉ΄μš΄νŠΈκ°€ 쀄어듀지 μ•Šκ³ , λ©”λͺ¨λ¦¬μ—μ„œ ν•΄μ œλ˜μ§€ λͺ»ν•˜λŠ” 상황을 λœ»ν•œλ‹€!

 

  • Observable 에 subscribe ν•  λ•Œ μ „λ‹¬λ˜λŠ” closure λ•Œλ¬Έμ— μˆœν™˜ μ°Έμ‘°κ°€ λ°œμƒν•  수 μžˆλ‹€.
  • Closure λŠ” μƒμ„±λ˜λŠ” μ‹œμ μ— ν΄λ‘œμ €μ—μ„œ μ ‘κ·Όν•˜λŠ” μ™ΈλΆ€ λ³€μˆ˜λ“€μ„ μΊ‘μ³λ§ν•˜μ—¬ κ°–κ³ μžˆλŠ”λ‹€. struct 같은 value type 이면 λ³΅μ‚¬λ˜μ§€λ§Œ, class object 라면 레퍼런슀λ₯Ό κ°–κ²Œλ˜μ–΄ 레퍼런슀 μΉ΄μš΄νŠΈκ°€ μ¦κ°€ν•˜κ²Œ λœλ‹€. μ΄λŸ¬ν•œ closure λ₯Ό ν•΄μ œν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, μˆœν™˜ μ°Έμ‘°κ°€ λ°œμƒλ˜λŠ” 것이닀.
  • Observable 을 μ‹€ν–‰ν•œ ν›„, Completed / Error / Dispose 등에 μ˜ν•΄ λλ‚˜κ²Œ λœλ‹€λ©΄, Observable 이 μ‚¬λΌμ§€κ²Œ λ˜μ–΄ 참쑰도 사라지고 λ©”λͺ¨λ¦¬κ°€ ν•΄μ œλœλ‹€.
  • ν•˜μ§€λ§Œ, UI μž‘μ—…μ˜ 경우 λ¬΄ν•œνžˆ μ§„ν–‰λ˜μ–΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— Completed, Error 등이 μ „λ‹¬λ˜μ§€ μ•Šμ•„ Observable 이 사라지지 μ•Šκ³ , closure 에 μ˜ν•œ μˆœν™˜ μ°Έμ‘°κ°€ λ°œμƒν•  수 μžˆλ‹€.
  • μˆœν™˜ μ°Έμ‘°κ°€ λ°œμƒν•˜μ§€ μ•ŠκΈ° μœ„ν•΄ closure 내뢀에 [weak self] ν‚€μ›Œλ“œλ₯Ό μž‘μ„±ν•΄ strong 이 μ•„λ‹Œ weak 레퍼런슀 μ°Έμ‘°λ₯Ό ν•˜κ²Œν•  수 μžˆλ‹€.

 

βœ”οΈŽ Thread λΆ„κΈ°

 

  • κΈ°μ‘΄ μ½”λ“œμ—μ„œλŠ” DispatchQueue.main.async, global.async 등을 μ‚¬μš©ν•΄μ„œ λ©”μΈμ“°λ ˆλ“œμ™€ λ³‘λ ¬μ“°λ ˆλ“œλ₯Ό κ΅¬λΆ„ν–ˆλ‹€.
  • RxSwift μ—μ„œ μ œκ³΅ν•˜λŠ” Observable 의 μŠ€μΌ€μ₯΄λŸ¬λ₯Ό μ§€μ •ν•˜λŠ” observe(on:), Subscribe 의 μŠ€μΌ€μ₯΄λŸ¬λ₯Ό μ§€μ •ν•˜λŠ” subscribe(on:) operator λ₯Ό μ΄μš©ν•˜λ©΄ μ“°λ ˆλ“œλ₯Ό μ‰½κ²Œ ꡬ뢄할 수 μžˆλ‹€.
  • 참고둜, κ°•μ˜μ—μ„œλŠ” observeOn(), subscribeOn() 을 μ΄μš©ν•˜μ§€λ§Œ μ΄λŠ” deprecated λ˜μ–΄ μœ„μ— μž‘μ„±λœ operator λ₯Ό μ΄μš©ν•˜λ„λ‘ ν•˜μž.

 

πŸ‘€ observe(on:), subscribe(on:) κ³Ό upStream, downStream ?

 

  • observeOn:: ν˜„μž¬ Observable 의 λ‹€μŒ Observable 이 싀행될 μ“°λ ˆλ“œλ₯Ό λ³€κ²½ν•œλ‹€. λ°‘μœΌλ‘œ 영ν–₯을 μ£Όλ‹ˆκΉŒ down stream 의 thread λ₯Ό λ°”κΎΈλŠ” 것이닀.
  • subscribeOn:: subscribe λ₯Ό ν•˜λŠ” μ‹œμ μ˜ Observable 이 싀행될 μ“°λ ˆλ“œλ₯Ό λ³€κ²½ν•œλ‹€. operator λ₯Ό ν˜ΈμΆœν•˜λŠ” μ‹œμ κ³Ό 상관없이, subscribe ν•˜λŠ” μ‹œμ μ˜ μ“°λ ˆλ“œλ₯Ό μ§€μ •ν•˜λŠ” μš©λ„μ΄λ‹€. μœ„λ‘œ 영ν–₯을 μ£Όλ‹ˆκΉŒ up stream 의 thread λ₯Ό λ°”κΎΈλŠ” 것이닀.

 

 

 

728x90
728x90