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

๐ŸŽ iOS & Swift

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€?

๋“ค์–ด๊ฐ€๊ธฐ์ „์—

Rx, Reactive Programming์ด ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ž˜ํ•˜๊ธฐ ์œ„ํ•œ ๋…ธ๋ ฅ์ด๋ผ๊ณ  ์ด์ „ ์‹œ๊ฐ„(Reactive Programming ํŽธ)์— ์ด์•ผ๊ธฐํ–ˆ๋Š”๋ฐ ๊ทธ๋Ÿผ ๋น„๋™๊ธฐ? ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๋ฌด์—‡์ผ๊ฐ€์š”? ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ฃ .

 


 

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ?

iOS ์•ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฒ„ํŠผ ํƒญ(ํด๋ฆญ)์— ๋ฐ˜์‘ํ•˜๊ธฐ
  • ํ‚ค๋ณด๋“œ๋ฅผ ํ…์ŠคํŠธ ํ•„๋“œ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜ํ•˜๋ฉด ํฌ์ปค์Šค๊ฐ€ ์‚ฌ๋ผ์ง
  • ์ธํ„ฐ๋„ท์—์„œ ํฐ ์‚ฌ์ง„ ๋‹ค์šด๋กœ๋“œ → ๋‹ค์šด๋กœ๋“œ ์ค‘์— ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰
  • ๋ฐ์ดํ„ฐ ๋น„ํŠธ๋ฅผ ๋””์Šคํฌ์— ์ €์žฅ
  • ์˜ค๋””์˜ค ์žฌ์ƒ

์ถœ์ฒ˜ : Raywenderich - ์—ฌ๊ธฐ ํด๋ฆญ

ํ•œ ๋ฒˆ ์ƒ๊ฐ์„ ํ•ด๋ณด๋ฉด ๊ฐ๊ฐ์˜ ์ž‘์—…๋“ค์€ ์„œ๋กœ์˜ ์‹คํ–‰์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์„œ๋กœ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก iOS๋Š” ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

 


 

Apple์˜ Cocoa and UIKit asynchronous APIs (๋น„๋™๊ธฐ API)

ํ•œ ๋ฒˆ์ฏค ์‚ฌ์šฉํ•ด๋ดค๊ฑฐ๋‚˜ ๋“ค์–ด๋ณธ ๋‚ด์šฉ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
Apple์€ iOS SDK์—์„œ ๋น„๋™๊ธฐ์‹ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•๋“ค์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • NotificationCenter
  • Delegate Pattern
  • Grand Central Dispatch(GCD)
  • Closures
  • Combine - iOS13๋ถ€ํ„ฐ ์ด์šฉ๊ฐ€๋Šฅํ•œ API

๋Œ€๋ถ€๋ถ„์˜ ํด๋ž˜์Šค๋“ค์€ ๊ฐœ๋ฐœ์ž์˜ ์˜๋„์™€ ๋‹ค๋ฅด๊ฒŒ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๊ณ ,
UI ์š”์†Œ์˜ ๊ฒฝ์šฐ๋„ ๋ณธ์งˆ์ ์œผ๋กœ ๋น„๋™๊ธฐ์ ์ž…๋‹ˆ๋‹ค.

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

 

 


 

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋‹ค ๋ณด๋ฉด ๊ฐ–๊ฒŒ ๋˜๋Š” ๋ฌธ์ œ ์˜์‹

๐Ÿ—ฃ ํด๋ž˜์Šค์™€ ํ•จ์ˆ˜์˜ ์ž‘๋™ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!

์–ด๋–ค ๊ฒƒ์ด ๋จผ์ € ๋ฆฌํ„ด๋ ์ง€, ์ž‘๋™ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์—†๊ธฐ ๋Œ€๋ฌธ์— ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค๋ณด๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋Ž์Šค๊ฐ€ ๋ณต์žกํ•ด์ง€๋Š” ์ฝ”๋“œ๊ฐ€ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

 

์ฝ”๋“œ ์˜ˆ์‹œ)

IBAction func onLoad() {
    editView.text = ""
    self.setVisibleWithAnimation(self.activityIndicator, true)
    
    downloadJson(MEMBER_LIST_URL) { json in
        self.editView.text = json
        self.setVisibleWithAnimation(self.activityIndicator, false)
        
        self.downloadJson(MEMBER_LIST_URL) { json in
            self.editView.text = json
            self.setVisibleWithAnimation(self.activityIndicator, false)
        }
        
        self.downloadJson(MEMBER_LIST_URL) { json in
            self.editView.text = json
            self.setVisibleWithAnimation(self.activityIndicator, false)
        }
        
        self.downloadJson(MEMBER_LIST_URL) { json in
            self.editView.text = json
            self.setVisibleWithAnimation(self.activityIndicator, false)
        }
        
        self.downloadJson(MEMBER_LIST_URL) { json in
            self.editView.text = json
            self.setVisibleWithAnimation(self.activityIndicator, false)
        }
    }
}

 

๐Ÿ—ฃ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ์ž‘์—…์ด ๋งŽ์•„์งˆ ๊ฒฝ์šฐ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง„๋‹ค.

Swift ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด Escaping Closure ๋ฐ Completion Handler๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๋งŽ์ด ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๋งŽ์€ ๋น„๋™๊ธฐ ์ž‘์—…, ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ, ๋น„๋™๊ธฐ ํ˜ธ์ถœ ๊ฐ„์˜ ์ œ์–ด ํ๋ฆ„์ด ๋ณต์žกํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ Apple์—์„œ ์ œ๊ณตํ•˜๋Š” API(ex. GCD)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋ฉด์„œ๋„ ์—ฌ๋Ÿฌ ๋ฌธ์ œ์ ์„ ๋Š๋ผ๊ฒŒ ๋˜์ฃ .
DispatchQueue๋‚˜ ํด๋กœ์ €๋งŒ์œผ๋กœ๋„ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅ์€ ํ•˜์ง€๋งŒ ์ฒ˜๋ฆฌํ•ด์•ผํ•  ์ž‘์—…์ด ๋งŽ์•„์งˆ ๊ฒฝ์šฐ ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ๋ณต์žกํ•ด์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ—ฃ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฒฝ์šฐ ์ฆ‰์‹œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š๋Š”๋‹ค.

๋‚˜์ค‘์— ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๋ฉด ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์งœ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. Completion Handler ๋ง๊ณ  Return ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€๊ฑฐ์ฃ .
๊ทธ๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด Rx์˜ Observable์ž…๋‹ˆ๋‹ค. (์šฐ๋ฆฌ๋Š” RxSwift์—์„œ์˜ Observable ์ด๊ฒ ์ฃ ?)

 

 

๋‚˜์ค‘์— ๋‹ค์‹œ ์•Œ์•„๋ณด๊ฒ ์ง€๋งŒ ์ •๋ฆฌํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Rx(Swift)๋ž€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ƒ๊ธฐ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ completion ๊ฐ™์€ closure๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ return ๊ฐ’์œผ๋กœ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋งŒ๋“ค์–ด์ง„ ์œ ํ‹ธ๋ฆฌํ‹ฐ(API)์ด๋‹ค.

 


 

๋น„๋™๊ธฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ํ•„์š”ํ•œ 4๊ฐ€์ง€

๋ชจ๋“  ๋น„๋™๊ธฐ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ํ•„์š”ํ•œ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‚˜๋จธ์ง€ ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ์—์„œ ์ฝ์–ด๋ณด์„ธ์š”.
์šฐ๋ฆฌ๋Š” ์ด ์ค‘์—์„œ ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ์— ์ง‘์ค‘ํ•ด๋ด…์‹œ๋‹ค.

  • ๋ช…์‹œ์  ์‹คํ–‰(Explicit execution)
  • ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋ฉด ๊ทธ๊ฒƒ์„ ์ปจํŠธ๋กคํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ์‰ฌ์šด ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ(Easy thread management)
  • ๐Ÿ—ฃ
    ๋น„๋™๊ธฐ์ž‘์—…์—์„œ ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ๊ฐ€ ํ•ต์‹ฌ์ด๋‹ค.
    ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—… ๋„์ค‘์ด๋‚˜ ์ž‘์—…์ด ๋๋‚œ ํ›„, (์˜ˆ๋ฅผ ๋“ค๋ฉด ๋„คํŠธ์›Œํ‚น ์ฒ˜๋ฆฌ ํ›„)
    ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค.
    
    ์ด ๋•Œ ์Šค๋ ˆ๋“œ(๋ฐฑ๊ทธ๋ผ์šด๋“œ) → ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ(๋ฉ”์ธ)๋กœ ์ž‘์—…์„ ๋„˜๊ฒจ์•ผ ํ•˜๋Š”๋ฐ
    ์Šค๋ ˆ๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ „ํ™˜ํ•˜๊ณ  ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ์ž‘์—…์„ ๋„˜๊ธธ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    
  • ์‰ฌ์šด ๊ตฌ์„ฑ๋ ฅ(Easily composable)
  • ๋น„๋™๊ธฐ์ž‘์—…์„ ์ƒ์„ฑํ•˜๊ณ  ์‹œ์ž‘ํ•˜๋ฉด ๊ทธ๊ฒƒ์€ ๋‹ค๋ฅธ ์–ด๋–ค ์Šค๋ ˆ๋“œ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์ž‘์—…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋…๋ฆฝ์ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ๋ถ€์ž‘์šฉ ์ตœ์†Œํ™”(Minimum the sid effects)
  • ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ์ˆ˜ํ–‰๋˜๋Š” ๋™์•ˆ ์Šค๋ ˆ๋“œ ์„œ๋กœ ๊ฐ„ ์˜ํ–ฅ์„ ๋ผ์น˜๋Š” ๋ถ€์ž‘์šฉ์„ ์ตœ์†Œํ™”ํ•ด์•ผํ•œ๋‹ค.

 


 

๋งˆ๋ฌด๋ฆฌ ์‹œ๊ฐ„

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

์šฐ๋ฆฌ๋Š” ๊ฐœ๋ฐœ์„ ํ•˜๊ฒŒ ๋  ๋•Œ ํ•„์ˆ˜๋ถˆ๊ฐ€๊ฒฐํ•˜๊ฒŒ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ ํ†ต์‹ ๋งŒ์„ ๋ณด๋”๋ผ๋„ ์šฐ๋ฆฌ๋Š” ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๊ฐ€ ์–ธ์ œ ๋„์ฐฉํ•  ์ง€ ๋ชจ๋ฅด๊ณ , ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๊ฐ€ ๋„์ฐฉํ•˜๋ฉด ์–ด๋–ค ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ฒŒ ๋˜์ฃ ? ์ด์ฒ˜๋Ÿผ ์šฐ๋ฆฌ๋Š” ์ž‘์—…์— ๋Œ€ํ•œ ์ˆœ์„œ๋ฅผ ํ•ญ์ƒ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋น„๋™๊ธฐ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ํ•„์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ์ 

๋น„๋™๊ธฐ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•  ๋•Œ์— ๋ณดํ†ต Closure์™€ Completion handler๋ฅผ ์ด์šฉํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ž‘์—…์ด ๋งŽ์•„์งˆ ๊ฒฝ์šฐ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฆฌํ„ด๊ฐ’์„ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋“ค๊ฒŒ ๋˜๋Š”๋ฐ ์ด ๋•Œ ์šฐ๋ฆฌ๋Š” RxSwift๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์š”์•ฝ

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€ ๊ฐ๊ฐ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์ž๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ณ , ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ž‘์—… ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค. 
๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํ•˜๋ฉด ์–ด๋–ค ์Šค๋ ˆ๋“œ๊ฐ€ ๋จผ์ € ์ž‘์—…์„ ๋งˆ์น ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

 


 

๋ ˆํผ๋Ÿฐ์Šค

https://gaki2745.github.io/swift/2019/10/13/Swift-RxSwift-01/

https://zeddios.tistory.com/1230

https://duda-programming.tistory.com/48

https://haningya.tistory.com/112

https://dev-daddy.tistory.com/25