Skip to content

๐Ÿฆ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ™œ์šฉํ•˜์—ฌ ์€ํ–‰ ์ฐฝ๊ตฌ ์—…๋ฌด ์Šค์ผ€์ค„์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ์•ฑ

Notifications You must be signed in to change notification settings

leeari95/ios-bank-manager

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

89 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ’ธ ์€ํ–‰ ์ฐฝ๊ตฌ ๋งค๋‹ˆ์ € ํ”„๋กœ์ ํŠธ

  • ํŒ€ ํ”„๋กœ์ ํŠธ(2์ธ)
  • ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„: 2021.12.20 ~ 2021.12.31

๋ชฉ์ฐจ

ํ‚ค์›Œ๋“œ

  • Queue
    • LinkedList
  • Generic
  • Protocol
  • Delegate Pattern
  • SOLID : SRP
  • Wildcard Pattern
  • Strong Reference Cycle
  • Core Foundation vs Foundation
  • CFAbsoluteTime Date
  • GCD
    • DispatchQueue
    • Semaphore
    • DispatchGroup
    • async sync
    • Serial Concurrent
  • UI ๊ตฌ์„ฑ (only Code)
  • Timer RunLoop
  • Custom View
  • Auto Layout

โญ๏ธ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

์€ํ–‰ ์ฐฝ๊ตฌ ์—…๋ฌด ์Šค์ผ€์ค„์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•œ ์•ฑ์ด์—์š”. ๐Ÿฆ

์†๋‹˜์ด ์ž…์žฅํ•œ ์ˆœ์„œ๋Œ€๋กœ ๋Œ€๊ธฐํ‘œ๋ฅผ ๋‚˜๋ˆ ์ฃผ๊ณ , ๋‘๊ฐœ์˜ ์ฐฝ๊ตฌ์—์„œ ๋งก์€ ์—…๋ฌด๋ฅผ ๋™์‹œ์— ์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•ด์š” ! ๐Ÿ’ช๐Ÿป


โœจ ํ”„๋กœ์ ํŠธ ์ฃผ์š”๊ธฐ๋Šฅ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๊ณ ๊ฐ ์ถ”๊ฐ€๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์—…๋ฌด๋ฅผ ๋Œ€๊ธฐ์ˆœ์„œ๋Œ€๋กœ ์‹œ์ž‘ํ•˜๊ณ , ๋ชจ๋“  ์—…๋ฌด๋ฅผ ๋งˆ์น˜๋ฉด ์—…๋ฌด์‹œ๊ฐ„ ํƒ€์ด๋จธ๊ฐ€ ์ผ์‹œ์ •์ง€ํ•ด์š”.

๐Ÿƒ๐Ÿปโ€โ™€๏ธ ์—…๋ฌด์ค‘์—๋„ ๊ณ ๊ฐ์„ ๋” ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์–ด์š”.

โŒ ์ดˆ๊ธฐํ™” ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ํ•˜๋˜ ์—…๋ฌด๋ฅผ ์ค‘์ง€ํ•˜๊ณ  ์€ํ–‰ ์—…๋ฌด๋ฅผ ์ข…๋ฃŒํ•ด์š”.


๐Ÿ›  Trouble Shooting

"์ฐธ์กฐํƒ€์ž…์„ ํ™œ์šฉํ•œ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ"

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

  • ์ด์œ  Queue๋ฅผ ์œ„ํ•œ LinkedList์ธ ์ ๋„ ์žˆ๊ณ , ๋˜ ๊ฐ ์š”์†Œ๋ฅผ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ˜๋ณต์ ์œผ๋กœ ํฌ์ธํ„ฐ๋ฅผ ์ถ”์ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ O(n)์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋งค์šฐ ๋น„ํšจ์œจ์ ์ธ ์ ์„ ํ•ด๊ฒฐํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

  • ํ•ด๊ฒฐ ํด๋ž˜์Šค์˜ ์ฐธ์กฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

    func append(_ value: Element) {
        let newNode = Node(value: value)
            
        if isEmpty {
            head = newNode
            tail = newNode
        } else {
            tail?.next = newNode
            tail = newNode
        }
    }

"์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์œผ๋กœ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค์˜ ์ฐธ์กฐ ์นด์šดํŠธ ์ƒํƒœ๋Š”?"

  • ์ƒํ™ฉ ๊ธฐ์กด์— ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์œผ๋กœ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑํ•œ ํƒ€์ž…์ด Delegate๋ฅผ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๋˜ ํ˜•ํƒœ์˜€๋‹ค. ์ดํ›„ ์ˆœํ™˜์ฐธ์กฐ ๋ฌธ์ œ๊ฐ€ ์šฐ๋ ค๋˜์–ด ๊ฐ ํƒ€์ž…๋“ค๋งˆ๋‹ค delegate ํ”„๋กœํผํ‹ฐ์— weak ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์ฃผ์—ˆ๋‹ค.

  • ์ด์œ  ๊ทธ๋Ÿฐ๋ฐ weak ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์ฃผ๋‹ˆ ํ•ด๋‹น ํƒ€์ž…์—์„œ ์ถœ๋ ฅํ•ด์ฃผ์—ˆ๋˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์•˜๋‹ค. init๊ณผ deinit์„ ํ†ตํ•ด ๋””๋ฒ„๊น…์„ ํ•ด๋ณด๋‹ˆ ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์œผ๋กœ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ํ•ด์ œ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์€ ๊ฐ’์„ ํ•ด์ฒดํ•˜๊ฑฐ๋‚˜ ๋ฌด์‹œํ•˜๋Š” ํŒจํ„ด์ค‘ ํ•˜๋‚˜์ด๋ฏ€๋กœ weak ํ‚ค์›Œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋จ๊ณผ ๋™์‹œ์— retain count๊ฐ€ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ํ•ด์ œ๋˜๋Š” ๊ฒƒ์ด์˜€๋‹ค.

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

    final class Bank {
        private let bankClerk: BankClerk
        private var customerQueue = Queue<Customer>()
        var delegate: BankDelegate? // weak ํ‚ค์›Œ๋“œ ์ œ๊ฑฐ
    ...
    }
    
    func run() {
        let bankClerk = BankClerk()
        let bank = Bank(bankClerk: bankClerk)
        let bankManager = BankManager(bank: bank)
        let _ = BankClerkViewController(bankClerk: bankClerk)
        let _ = BankViewController(bank: bank) 
    ...
    }

"์ง€๋ ˆ์ง์ž‘ํ•˜์—ฌ ์„ค๊ณ„ํ•˜์ง€ ๋ง๊ธฐ"

  • ์ƒํ™ฉ

    • ํŒ€์›์ธ ํ—ˆํ™ฉ๊ณผ ๋‚˜๋Š” ์ฝ˜์†”์•ฑ ๋‹ค์Œ ์Šคํ…์— ์žˆ์„ ViewController๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ž‘์—…๊นŒ์ง€ ์ถ”์ธกํ•˜์—ฌ ๋ฏธ๋ฆฌ ์ฝ˜์†”์•ฑ์„ ๊ตฌํ˜„ํ•  ๋•Œ๋ถ€ํ„ฐ Delegate ํŒจํ„ด๊นŒ์ง€ ๊ณ ๋ คํ•˜์—ฌ ์„ค๊ณ„๋ฅผ ํ•˜์˜€๋‹ค. (์œ„ ์‚ฌ์ง„์€ ๋‹น์‹œ ์ž‘์„ฑํ–ˆ๋˜ UML์ด๋‹ค.)
    • ๋ฆฌ๋ทฐ์–ด์—๊ฒŒ ์ฝ”๋“œ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ›๊ณ  ๋‹ค์‹œ ์‚ดํŽด๋ณด๋ฉฐ ๊ณ ๋ฏผํ•ด๋ณธ ๊ฒฐ๊ณผ, ์ฝ˜์†”์•ฑ์—์„œ ๋ถˆํ•„์š”ํ•œ ์—ญํ•  ๋ถ„๋ฆฌ๊ฐ€ ์ผ์–ด๋‚˜์„œ ์˜คํžˆ๋ ค ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋งค์šฐ ๋–จ์–ด์กŒ๋‹ค.
  • ์ด์œ 

    • ๋‹น์žฅ ๋งŒ๋“ค์–ด์•ผํ•  ๊ธฐ๋Šฅ์ด ์•„๋‹ˆ๋ผ ์ถ”ํ›„ ์ถ”๊ฐ€๋  ๊ธฐ๋Šฅ๊นŒ์ง€ ์ถ”์ธกํ•˜์—ฌ ์„ค๊ณ„ํ•œ ํƒ“์ด ํฐ ๋ฌธ์ œ์ ์ธ ๊ฒƒ ๊ฐ™๋‹ค.
  • ํ•ด๊ฒฐ

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

    • ๋‹ค์Œ ์Šคํ…์„ ์ง€๋ ˆ์ง์ž‘ํ•ด์„œ ๊ฐœ๋ฐœํ•˜์ง€ ๋ง์ž
    • ๊ทธ๋ƒฅ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž์ถฐ ์ตœ์†Œํ•œ์˜ ๊ธฐ๋Šฅ์„ ๋นจ๋ฆฌ ๋งŒ๋“ค์–ด๋ณด์ž.
    • ์‹œ๋„ํ•˜๊ณ  ์‹คํŒจํ•˜๊ณ  ๋Œ์•„๊ฐ€๋Š” ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋ฉฐ ๊ฐœ์„ ํ•ด๋‚˜๊ฐ€๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ง„ํ–‰ํ•˜์ž.

"Thread Safeํ•˜๊ฒŒ ์ฝ”๋“œ์งœ๋ณด๊ธฐ"

  • ์ƒํ™ฉ
    • ์€ํ–‰์›์˜ ์ˆ˜๋งŒํผ DispatchQueue๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ์žˆ๊ณ , ๊ทธ ์•ˆ์—์„œ dequeue๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๊ฐ์˜ ํ์— ์ ‘๊ทผํ•˜๊ณ  ์žˆ๋‹ค.
      • ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๊ณ ๊ฐ์˜ ํ๋ฅผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค.
      • ๊ทธ๋Ÿฌ๋‚˜ ํ˜„์žฌ ์šฐ๋ฆฌ ์ฝ”๋“œ์—์„œ๋Š” race condition์—†์ด ์ž˜ ์ž‘๋™ํ•œ๋‹ค. ์ด์œ ๊ฐ€ ๋ฌด์—‡์ผ๊นŒ?
  • ์ด์œ 
    1. ์ผ๋‹จ ์€ํ–‰์›์˜ ์ˆ˜(DispatchQueue)๊ฐ€ ์ ๋‹ค. 3๊ฐœ๋ฟ์ด๋‹ค. 
       ๋”ฐ๋ผ์„œ ์Šค๋ ˆ๋“œ๋Š” 3๊ฐœ ์ด์ƒ ์ƒ๊ธฐ์ง€ ์•Š๋Š”๋‹ค.
    2. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ์—…๋ฌด๋ฅผ ํ• ๋•Œ ์Šค๋ ˆ๋“œ๋ฅผ ์ž ์žฌ์šด๋‹ค. ๋”œ๋ ˆ์ด๊ฐ€ ์žˆ๋‹ค.
    3. ๊ณ ๊ฐ์˜ ์ˆซ์ž๋„ ์ ์€ํŽธ์ด๋‹ค.
    
    • ๋”ฐ๋ผ์„œ ๊ฒฐ๋ก ์€ ํ˜„์žฌ ์…‹ํŒ…(์€ํ–‰์› ์ˆ˜, ๊ณ ๊ฐ ์ˆ˜, ๋”œ๋ ˆ์ด) ๋•Œ๋ฌธ์— race condition์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ํŒ๋‹จ์ด ๋“ค์—ˆ๋‹ค.
    • ํ˜„์žฌ๋Š” race condtion์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜์ง€๋งŒ, ๊ฒฐ๊ตญ์— Queue๋Š” Thread-Safe ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, race condition์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ ๋„ ์žฅ๋‹ดํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒฐ๋ก ์ด๋‹ค.
      • ๋”ฐ๋ผ์„œ DispatchSemaphore๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์Šค๋ ˆ๋“œ์˜ ์ˆ˜๋ฅผ ์ œํ•œํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•  ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
      • ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•๋„ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ customers.dequeue ์ž‘์—…๋“ค์ด for๋ฌธ์œผ๋กœ ์ธํ•ด ์ž‘์—…์ด ์Œ“์—ฌ์žˆ๊ณ , ํ์˜ ์ ‘๊ทผ์„ ์„ธ๋งˆํฌ์–ด๋กœ ์ œํ•œํ•˜๊ณ  ์žˆ์œผ๋‹ˆ, ์ œํ•œํ•˜๋Š” ๋™์•ˆ ์Œ“์ธ ์ž‘์—…๋“ค์ด ์ œํ•œ์ด ํ’€๋ฆฌ๊ณ  ์‹คํ–‰๋˜๋ฉด ๋น„์–ด์žˆ๋Š” ํ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— fatalError๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•ด๊ฒฐ
    • ํ˜„์žฌ global()๋กœ ๋™์‹œ์„ฑํ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์„ Serial Queue๋กœ ๋งŒ๋“ค์–ด์„œ ์งˆ์„œ๋ฅผ ์ง€ํ‚ค๊ฒŒ ํ•ด์ฃผ๋ฉด ๋งค์šฐ ์•ˆ์ „ํ•  ๊ฒƒ ๊ฐ™๋‹ค. ๐Ÿ‘
      • ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, race condition ๋ฐœ์ƒ ํ•˜์ง€ ์•Š์•˜๋‹ค!!!!!
  • ๊ฐœ์„ ๋œ ์ฝ”๋“œ
    • ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ Serial Queue๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ  DispatchQueue.global() ๋Œ€์‹  ์ง์ ‘ ์ƒ์„ฑํ•ด์ค€ bankerQueue๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐœ์„ ํ•˜์˜€๋‹ค.
      • DispatchQueue๊ฐ€ ์ง€์—ญ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฉค๋ฒ„๋ณ€์ˆ˜์—ฌ์•ผํ•˜๋Š” ์ด์œ ๋Š” ๋ญ˜๊นŒ?
        • DispatchQueue์— ๋น„๋™๊ธฐ๋กœ ํ๋ฅผ ๋ณด๋‚ด๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์ด for๋ฌธ์— ์˜ํ•ด 4๋ฒˆ ๋ถˆ๋ฆฐ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ, ์ง€์—ญ๋ณ€์ˆ˜๋กœ DispatchQueue๊ฐ€ 4๊ฐœ, ์ฆ‰ ๊ฐ๊ฐ์˜ ์ž‘์—…๋งˆ๋‹ค ์ƒ์„ฑ๋ ํ…Œ๋‹ˆ ์‹ค์งˆ์ ์œผ๋กœ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์•„์ฃผ์ง€ ๋ชปํ•  ๊ฒƒ์ด๋‹ค.
        • ๋”ฐ๋ผ์„œ for๋ฌธ ๋‚ด๋ถ€์—์„œ Queue๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฐ”๊นฅ์—์„œ ์ƒ์„ฑํ•ด์„œ, ๊ทธ ํ•ด๋‹น ํ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค.
        • Semaphore๋ฅผ ํ™œ์šฉํ•  ๋•Œ์—๋„ ์œ„์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฉค๋ฒ„๋ณ€์ˆ˜์—ฌ์•ผ ํ•œ๋‹ค!!!!

"๋ทฐ์˜ ์š”์†Œ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ"

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

  • ์ด์œ  ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์‹œ ๋ทฐ๋ฅผ ๊ทธ๋ฆฌ๋Š” ์ž‘์—…์€ main thread์—์„œ ์ฒ˜๋ฆฌํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ์ง€ ์•Š์•„์„œ ํ•ด๋‹น ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.
  • ํ•ด๊ฒฐ ๋ทฐ๋ฅผ ๊ทธ๋ฆฌ๋Š” ์ž‘์—…์„ main thread์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก DispatchQueue.main.async ํด๋กœ์ € ๊ตฌ๋ฌธ์•ˆ์— ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค.

"๋ฉˆ์ถ”์ง€ ์•Š๋Š” ํƒ€์ด๋จธ"

  • ์ƒํ™ฉ ๊ณ ๊ฐ ์ถ”๊ฐ€๋ฒ„ํŠผ์„ ์—ฌ๋Ÿฌ๋ฒˆ ํด๋ฆญํ•˜๊ณ  ์ดˆ๊ธฐํ™”๋ฅผ ๋ˆ„๋ฅด๊ฒŒ ๋˜๋ฉด ํƒ€์ด๋จธ๊ฐ€ ๋ฉˆ์ถ”์ง€ ์•Š์•˜๋‹ค.

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


๐Ÿ”ฅ ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฒƒ

"์ฝ”๋“œ์—์„œ ๊ฒฝ์Ÿ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•"

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

  • Xcode์—์„œ ..
    • Product > scheme > editScheme > Run > Diagnostics > Thread Sanitizer
    • Thread Sanitizer ์ด๊ฑธ ์ฒดํฌํ•˜๋ฉด ๋นŒ๋“œ๋ฅผ ๋Œ๋ฆฌ๊ณ  ๋‚˜์„œ thread safe ํ•˜์ง€ ์•Š์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ์—‘์Šค์ฝ”๋“œ์—์„œ ์ฒดํฌํ•ด์ค€๋‹ค.
    • ํ•˜์ง€๋งŒ ์‚ฌ์šฉํ•ด๋ณด๋‹ˆ ์™„๋ฒฝํ•˜๊ฒŒ ์ฒดํฌํ•ด์ฃผ๋Š” ๊ฑด ์•„๋‹Œ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ƒฅ ๋„์™€์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์‚ฌ์šฉํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.

Thread Safeํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด?

  • ๊ณต์œ ์ž์›์„ ์ฝ๊ณ  ์“ฐ๋Š” ์ž‘์—…์„ Thread safeํ•˜๊ฒŒ Shemaphore๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•˜๋‚˜์˜ thread๋งŒ ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
    • ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์€ ์™„๋ฒฝํ•˜๊ฒŒ ์ œ์–ดํ•˜๊ธฐ๋Š” ๋ฌด๋ฆฌ๊ฐ€ ์žˆ๋‹ค. ์˜คํžˆ๋ ค ๊ณต์œ ์ž์›์„ lock์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋‹ค๊ฐ€ ๊ต์ฐฉ ์ƒํ™ฉ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค๊ณ  ํ•œ๋‹ค.
  • Serial Queue sync๋กœ ๋ณด๋‚ด์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.
    • ๊ทธ๋Ÿฌ๋ฉด ๋“ค์–ด์˜จ task์— ์ˆœ์„œ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์ˆ˜์˜ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ๊ฐ’์„ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๋Š” ์ƒํ™ฉ์ด ๋œ๋‹ค.
    • sync๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” Serial queue๋กœ ๋ณด๋‚ธ ์ž‘์—…์„ ๊ธฐ๋‹ค๋ฆผ์œผ๋กœ์จ ๊ณต์œ ์ž์›์˜ ์ œ๋Œ€๋กœ ๋œ ๊ฐ’์„ ์–ป๊ธฐ ์œ„ํ•จ์ด๋‹ค.

"Core Foundation vs Foundation"

CFAbsoluteTime ํƒ€์ž… ๋Œ€์‹ ์— Date ํƒ€์ž…์„ ํ™œ์šฉํ•˜์—ฌ ์—ฐ์‚ฐ์‹œ๊ฐ„ ์ธก์ •ํ•˜๋„๋ก ์ˆ˜์ •ํ•˜์˜€๋‹ค. Core Foundation ๋‚ด์žฅํ•จ์ˆ˜๋ณด๋‹ค Foundation์— ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์˜ณ๋‹ค๊ณ  ํŒ๋‹จ๋˜์—ˆ๋‹ค.

  • ์ฝ”์–ด ํŒŒ์šด๋ฐ์ด์…˜์— ์žˆ๋Š” ๊ธฐ๋Šฅ์€ Foundation์—์„œ ๋ž˜ํ•‘ํ•˜์—ฌ ๊ตฌํ˜„๋˜์–ด์ ธ์žˆ๋‹ค.
  • ๋ณดํ†ต ์•ฑ๊ฐœ๋ฐœ์„ ํ•  ๋•Œ์—๋Š” Foundation์˜ ๊ธฐ๋Šฅ ์—†์ด ๊ฐœ๋ฐœํ•˜๊ธฐ์—๋Š” ์–ด๋ ค์›€์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, Core Foundation์— ๋‚ด์žฅ๋˜์–ด์žˆ๋Š” ๊ธฐ๋Šฅ๋ณด๋‹ค๋Š” Foundation์— ๋‚ด์žฅ๋˜์–ด์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•˜๋Š” ํŽธ์ด๋‹ค.

"๊ตฌ์กฐ์ฒด ํ”„๋กœํผํ‹ฐ๋Š” ํด๋กœ์ € ๋‚ด๋ถ€์—์„œ ์™œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š”๊ฐ€?"

  • ์ƒํ™ฉ ํ”„๋กœ์ ํŠธ์—์„œ ย Bank ํƒ€์ž…์€ย ๊ตฌ์กฐ์ฒด์ด๊ณ , numberOfCustomers ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์€ํ–‰์›์ด ์ผ์„ ํ•  ๋•Œ, ์ฒ˜๋ฆฌํ•œ ๊ณ ๊ฐ์˜ ์ˆ˜๋ฅผย Dispatch.global().asyncย ํด๋กœ์ € ๋‚ด์—์„œ ์นด์šดํŠธ(numberOfCustomers) ํ•ด์ฃผ๋„๋ก ํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.
  • ์ด์œ  Escaping closure์˜ ๊ฒฝ์šฐ ๊ตฌ์กฐ์ฒด์—์„œ๋Š” ์บก์ณ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
// ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ์˜ˆ์‹œ
struct SomeStruct {
    var num = 0
    
    private mutating func test() {
        let closure = { // Escaping closure captures mutating 'self' parameter
            self.num += 1
        }
        closure()
    }
}
  • Escaping closure์˜ ๊ฒฝ์šฐ ๊ตฌ์กฐ์ฒด์—์„œ๋Š” ์บก์ณ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

    class์™€ ๊ฐ™์€ ์ฐธ์กฐ ํƒ€์ž…์ด ์•„๋‹Œ Struct, enum๊ณผ ๊ฐ™์€ ๊ฐ’ํƒ€์ž…์—์„œ๋Š” mutating reference์˜ ์บก์ณ๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— self ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅ ํ•˜๋‹ค.

  • ํ•ด๊ฒฐ Bank ํƒ€์ž…์„ ํด๋ž˜์Šค๋กœ ๋ฐ”๊ฟ”์ฃผ์—ˆ๋‹ค.

"DispatchQueue๋Š” ์ค‘๊ฐ„์— ์ž‘์—…์„ ์ค‘์ง€์‹œํ‚ฌ ์ˆ˜ ์žˆ์„๊นŒ?"

  • cancel ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋”๋ผ๋„ ์ž‘์—…์ด ์ž‘์—… ์ค‘์ด๋ผ๋ฉด ์ค‘์ง€์‹œํ‚ฌ ์ˆ˜ ์—†๋‹ค.
  • ์šฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•˜์ง€๋งŒ GCD๊ฐ€ ์ž‘์—…์„ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ํ•˜๋Š” ๊ฒƒ์€ ํ•  ์ˆ˜๋Š” ์—†๋‹ค.
  • Operation Queue๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘์—… ์ค‘์ธ ์ž‘์—…์„ ์ค‘์ง€ ํ•  ์ˆ˜ ์žˆ๋‹ค. [์ฐธ๊ณ  ๋งํฌ]

top

[ํ•™์Šต ๊ธฐ๋ก ํ”์ ]

๋ชฉ์ฐจ

STEP 1 : ํ ํƒ€์ž… ๊ตฌํ˜„

์€ํ–‰์— ๋„์ฐฉํ•œ ๊ณ ๊ฐ์ด ์ž„์‹œ๋กœ ๋Œ€๊ธฐํ•  ๋Œ€๊ธฐ์—ด ํƒ€์ž…์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

1-1 ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ

  • ์–‘๋ฐฉํ–ฅ LinkedList vs ๋‹จ๋ฐฉํ–ฅ LinkedList
    • ์„œ๋กœ ์ด์•ผ๊ธฐ๋ฅผ ๋‚˜๋ˆ„๋ฉด์„œ ๋‹จ๋ฐฉํ–ฅ์œผ๋กœ๋„ ์ถฉ๋ถ„ํžˆ ํ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ฆ.
    • ๋…ธ๋“œ๋ฅผ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๊ณ  ์ฐธ์กฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.
  • ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ Mock ํƒ€์ž… ์ƒ์„ฑ
    • ํ…Œ์ŠคํŠธ ์ง„ํ–‰์‹œ Node, LinkedList์˜ head, tail์˜ ์š”์†Œ๋ฅผ ์ ‘๊ทผํ•˜์—ฌ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ–ˆ๋‹ค.
    • ํ•ด๋‹น ์š”์†Œ๋“ค์€ ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•˜๋ฉด ์•ˆ๋œ๋‹ค๋Š” ํŒ๋‹จ์ด ๋“ค์–ด์„œ ๋”ฐ๋กœ MockLinkedList๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์–ด ์›ํ™œํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.
  • attribute๋ฅผ ํ™œ์šฉ
    • ๋ฐ˜ํ™˜ ๊ฐ’์„ ์œ ์˜๋ฏธํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋ฒ„๋ ค๋„๋˜๋Š” remove ๊ด€๋ จ ๋ฉ”์†Œ๋“œ์— ์†์„ฑ @discardableResult์„ ๋ถ€์—ฌํ•˜์—ฌ ์ปดํŒŒ์ผ๋Ÿฌ ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•˜์˜€๋‹ค.

1-2 ์˜๋ฌธ์ 

  • if vs guard

    // 1. if ๊ตฌ๋ฌธ
    func removeFirst() -> Element? {
        if isEmpty {
            return nil
        }
        let result = head?.value
        head = head?.next
        
        return result
    }
    // 2. guard ๊ตฌ๋ฌธ
    func removeFirst() -> Element? {
        guard isEmpty == false else {
            return nil
        }
        let result = head?.value
        head = head?.next
        
        return result
    }
  • if๋ฌธ์œผ๋กœ ๊ตฌํ˜„ ์‹œ ์กฐ๊ฑด๋ฌธ์ด ๊น”๋”ํ•˜๊ฒŒ isEmpty๋กœ ๋งž์•„๋–จ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

    • guard๋ฌธ์ด๋“  if๋ฌธ์ด๋“  ๋ฉ”์†Œ๋“œ ์‹œ์ž‘๋ถ€๋ฌธ์—์„œ return์„ ํ™œ์šฉํ•˜์—ฌ ๋ฉ”์†Œ๋“œ๋ฅผ ํƒˆ์ถœํ•˜๋Š”๊ฑด ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋“  ์ƒ๊ด€์—†๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
  • guard๋ฌธ

    • guard ๊ตฌ๋ฌธ์˜ ๊ธฐ๋Šฅ์€ ์ฝ”๋“œ ๋ธ”๋Ÿญ์˜ ๋น ๋ฅธ ์ข…๋ฃŒ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ํ•จ์ˆ˜ ์ „์ฒด ํ๋ฆ„์„ ๋ดค์„ ๋•Œ guard ๊ตฌ๋ฌธ์ด ๊ฐ€๋…์„ฑ์ด ๋” ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. guard๋ฌธ๋งŒ ๋ณด๋”๋ผ๋„ ํ•จ์ˆ˜๋ฅผ ํƒˆ์ถœํ•˜๋Š” ๊ตฌ๋ฌธ์ด๋ผ๊ณ  ์ฝํ˜€์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    • if๋ฌธ ์ฒ˜๋Ÿผ ์กฐ๊ฑด๋ฌธ์ด ๊น”๋”ํ•˜์ง€๋Š” ๋ชปํ•˜๊ฒŒ ๋˜์—ˆ์ง€๋งŒ, ํ•จ์ˆ˜๋ฅผ ํƒˆ์ถœํ•˜๋Š” ๋ถ€๋ถ„์„ guard๋ฌธ์œผ๋กœ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

1-3 Trouble Shooting

[1] ์ฐธ์กฐํƒ€์ž…์„ ํ™œ์šฉํ•œ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ

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

  • ์ด์œ  Queue๋ฅผ ์œ„ํ•œ LinkedList์ธ ์ ๋„ ์žˆ๊ณ , ๋˜ ๊ฐ ์š”์†Œ๋ฅผ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ˜๋ณต์ ์œผ๋กœ ํฌ์ธํ„ฐ๋ฅผ ์ถ”์ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ O(n)์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋งค์šฐ ๋น„ํšจ์œจ์ ์ธ ์ ์„ ํ•ด๊ฒฐํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

  • ํ•ด๊ฒฐ ํด๋ž˜์Šค์˜ ์ฐธ์กฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

    func append(_ value: Element) {
        let newNode = Node(value: value)
            
        if isEmpty {
            head = newNode
            tail = newNode
        } else {
            tail?.next = newNode
            tail = newNode
        }
    }

1-4 ๋ฐฐ์šด ๊ฐœ๋…

  • Linked-list ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ดํ•ด
  • Queue ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ดํ•ด

1-5 PR ํ›„ ๊ฐœ์„ ์‚ฌํ•ญ

  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋‚ด๋ถ€์—์„œ overrideํ•œ ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์— super ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์ˆ˜์ •
  • LinkedList๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•œ Mock ๊ฐ์ฒด ์‚ญ์ œ
    • LinkedList ํƒ€์ž…์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœํผํ‹ฐ, ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋„๋ก ๋ฆฌํŒฉํ† ๋ง
  • ํ…Œ์ŠคํŠธ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์„ ์ ์ ˆํ•˜๊ฒŒ ์ˆ˜์ •
  • QueueTests์—์„œย setUp()ย ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋„๋ก ์ˆ˜์ •

top


STEP 2 : ํƒ€์ž… ๊ตฌํ˜„ ๋ฐ ์ฝ˜์†”์•ฑ ๊ตฌํ˜„

์€ํ–‰๊ณผ ๊ณ ๊ฐ์˜ ํƒ€์ž…์„ ๊ตฌํ˜„ํ•˜๊ณ  ์ฝ˜์†”์•ฑ์„ ๊ตฌํ˜„ํ•œ๋‹ค.

2-1 ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ

  • ๊ตฌํ˜„ํ•œ ํƒ€์ž…๋“ค ๊ฐ๊ฐ ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ–๋„๋ก ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • ์ถœ๋ ฅ๋ฌธ๊นŒ์ง€๋„ ์€ํ–‰์›, ์€ํ–‰์ด ํ•ด์•ผํ•  ์ผ์ด ์•„๋‹ˆ๋ผ๊ณ  ํŒ๋‹จ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ถœ๋ ฅ๋งŒ ํ•˜๋Š” ํƒ€์ž…(ViewController)์„ ๋งŒ๋“ค์–ด Delegate ํŒจํ„ด์„ ํ™œ์šฉํ•˜์—ฌ ๋ถ„๋ฆฌํ•ด์ฃผ์—ˆ๋‹ค.
    • ์š”๊ตฌ์‚ฌํ•ญ ์˜ˆ์‹œ์— ๋งž์ถฐ ์ถœ๋ ฅ์„ ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด NumberFormatter๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ถ€๋ถ„์ด ํ•„์š”ํ–ˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์€ ์€ํ–‰์—์„œ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฑด ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋”ฐ๋กœ ํƒ€์ž…์œผ๋กœ ๋นผ์ฃผ์–ด static ๋ฉ”์†Œ๋“œ๋กœ ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋‹ค.
  • ์ˆœํ™˜์ฐธ์กฐ
    • Delegate ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ชจ๋ธ ํƒ€์ž… ๋ณ„๋กœ viewController๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.
    • ๋ชจ๋ธ ํƒ€์ž…์€ delegate๋กœ viewController๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  viewController์€ ์ž๊ธฐ ์ž์‹ ์„ delegate๋กœ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•ด ๋ชจ๋ธ ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
    • ๋ชจ๋ธ ํƒ€์ž…์˜ delegate๋ฅผ weak ํ‚ค์›Œ๋“œ(์•ฝํ•œ ์ฐธ์กฐ)๋ฅผ ์‚ฌ์šฉํ•ด ์ˆœํ™˜์ฐธ์กฐ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Delegate ํŒจํ„ด ์ž‘์„ฑ์‹œ ๋„ค์ด๋ฐ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์„ ํ•ด๋ณด์•˜๋‹ค.
    • ๊ตฌ๊ธ€์˜ Swift Style Guide๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋„ค์ด๋ฐ์„ ํ•˜์˜€๋‹ค.

      The term โ€œdelegateโ€™s source objectโ€ refers to the object that invokes methods on the delegate. For example, aย UITableViewย is the source object that invokes methods on theย UITableViewDelegateย that is set as the viewโ€™sย delegateย property.

2-2 ์˜๋ฌธ์ 

  • Delegate ํŒจํ„ด ๊ตฌํ˜„์„ ์œ„ํ•ด ๊ธฐ์กด ๋ชจ๋ธ ํƒ€์ž…์— ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ƒ๊ฒผ๋Š”๋ฐ ์ด๊ฒŒ ์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ์ธ์ง€ ์ž˜ ํŒ๋‹จ์ด ์„œ์งˆ ์•Š๋Š”๋‹ค.
    • ๊ธฐ์กด ๊ตฌ์กฐ์ฒด์˜€๋˜ ํƒ€์ž…๋“ค์„ class๋กœ ๋ณ€๊ฒฝํ•ด์ค€ ๋ถ€๋ถ„์ด ์ถ”ํ›„ retain count ์ถ”์  ๋น„์šฉ์ด ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋ผ๋Š” ์šฐ๋ ค๊ฐ€ ์ƒ๊ฒผ๋‹ค.
  • Delegate ํŒจํ„ด ์‚ฌ์šฉ์‹œ ๊ฐ•ํ•œ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฐœ์ƒ์„ ์˜ˆ๋ฐฉํ•˜๊ธฐ ์œ„ํ•ด weak ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์ฃผ์—ˆ๋”๋‹ˆ ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์œผ๋กœ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ํ•ด์ œ๊ฐ€ ๋˜์—ˆ๋‹ค.
    • ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ์ฐธ์กฐ๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด weak ํ‚ค์›Œ๋“œ ๋ณด๋‹ค๋Š” ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•œ ๊ฒƒ์ผ๊นŒ?
  • ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์— ๋งž๊ฒŒ ์—ญํ• ์„ Delegate ํŒจํ„ด์„ ํ™œ์šฉํ•˜์—ฌ ๋ถ„๋ฆฌํ•ด์ฃผ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ™•์žฅ์„ฑ์„ ๊ณ ๋ คํ–ˆ์„ ๋•Œ ์ด๊ฒŒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค๊ณ„ํ•œ ๊ฒƒ์ด ๋งž๋Š”์ง€ ๋„ˆ๋ฌด ์˜ค๋ฒ„ ์—”์ง€๋ฆฌ์–ด๋‹ํ•œ ๋ถ€๋ถ„์€ ์•„๋‹Œ์ง€ ํŒ๋‹จ์ด ์–ด๋ ต๋‹ค.

2-3 Trouble Shooting

[1] ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์œผ๋กœ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค์˜ ์ฐธ์กฐ ์นด์šดํŠธ ์ƒํƒœ๋Š”?

  • ์ƒํ™ฉ ๊ธฐ์กด์— ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์œผ๋กœ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑํ•œ ํƒ€์ž…์ด Delegate๋ฅผ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๋˜ ํ˜•ํƒœ์˜€๋‹ค. ์ดํ›„ ์ˆœํ™˜์ฐธ์กฐ ๋ฌธ์ œ๊ฐ€ ์šฐ๋ ค๋˜์–ด ๊ฐ ํƒ€์ž…๋“ค๋งˆ๋‹ค delegate ํ”„๋กœํผํ‹ฐ์— weak ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์ฃผ์—ˆ๋‹ค.

    final class Bank {
        private let bankClerk: BankClerk
        private var customerQueue = Queue<Customer>()
        weak var delegate: BankDelegate?
    ...
    }
    
    func run() {
        let bankClerk = BankClerk()
        let bank = Bank(bankClerk: bankClerk)
        let bankManager = BankManager(bank: bank)
        let _ = BankClerkViewController(bankClerk: bankClerk)
        let _ = BankViewController(bank: bank) // 
    ...
    }
  • ์ด์œ  ๊ทธ๋Ÿฐ๋ฐ weakํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์ฃผ๋‹ˆ ํ•ด๋‹น ํƒ€์ž…์—์„œ ์ถœ๋ ฅํ•ด์ฃผ์—ˆ๋˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์•˜๋‹ค. init๊ณผ deinit์„ ํ†ตํ•ด ๋””๋ฒ„๊น…์„ ํ•ด๋ณด๋‹ˆ ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์œผ๋กœ ์ƒ์„ฑํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ํ•ด์ œ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์€ ๊ฐ’์„ ํ•ด์ฒดํ•˜๊ฑฐ๋‚˜ ๋ฌด์‹œํ•˜๋Š” ํŒจํ„ด์ค‘ ํ•˜๋‚˜์ด๋ฏ€๋กœ weak ํ‚ค์›Œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋จ๊ณผ ๋™์‹œ์— retain count๊ฐ€ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ํ•ด์ œ๋˜๋Š” ๊ฒƒ์ด์˜€๋‹ค.

  • ํ•ด๊ฒฐ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” viewController(์€ํ–‰์›, ์€ํ–‰)๋ฅผ ์ƒ์ˆ˜์— ๋‹ด์œผ๋ฉด xcode์—์„œ ๊ณ ๋ฉ”์„ธ์ง€๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค. ์™€์ผ๋“œ ์นด๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด์„œ ์ˆœํ™˜์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จ๋˜์–ด weak ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.

    final class Bank {
        private let bankClerk: BankClerk
        private var customerQueue = Queue<Customer>()
        var delegate: BankDelegate?
    ...
    }
    
    func run() {
        let bankClerk = BankClerk()
        let bank = Bank(bankClerk: bankClerk)
        let bankManager = BankManager(bank: bank)
        let _ = BankClerkViewController(bankClerk: bankClerk)
        let _ = BankViewController(bank: bank) 
    ...
    }

2-4 ๋ฐฐ์šด ๊ฐœ๋…

  • ํƒ€์ž… ์ถ”์ƒํ™” ๋ฐ ์ผ๋ฐ˜ํ™”
  • Delegate ํŒจํ„ด ํ™œ์šฉ
  • SOLID์˜ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™
  • ์™€์ผ๋“œ์นด๋“œ ํŒจํ„ด๊ณผ weak ํ‚ค์›Œ๋“œ์˜ ๊ด€๊ณ„

2-5 PR ํ›„ ๊ฐœ์„ ์‚ฌํ•ญ

  • ๊ฐœ๋ฐœํ•  ๋•Œ ์—ผ๋‘ํ•ด์•ผํ•  ๊ฒƒ
    • ๊ธฐ๋Šฅ์„ ์„ ํƒํ•  ๋•Œ์—๋Š” ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์€ ๋ฌด์—‡์ด ์žˆ๋Š”์ง€ ํƒ์ƒ‰ํ•˜๊ธฐ.
    • ์„ ํƒํ•œ ๊ธฐ๋Šฅ์ด ๋‹ค๋ฅธ ๊ธฐ๋Šฅ๋ณด๋‹ค ๋‚˜์€์ ์€ ๋ญ๊ฐ€ ์žˆ๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด๊ธฐ
    • ๊ธฐ๋Šฅ์„ ์ฐพ์•„ ์‚ฌ์šฉํ•  ๋•Œ ์„ ํƒํ•œ ์ด์œ ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๊ธฐ
  • CFAbsoluteTime ํƒ€์ž… ๋Œ€์‹ ์— Date ํƒ€์ž…์„ ํ™œ์šฉํ•˜์—ฌ ์—ฐ์‚ฐ์‹œ๊ฐ„ ์ธก์ •ํ•˜๋„๋ก ์ˆ˜์ •
    • Core Foundation ๋‚ด์žฅํ•จ์ˆ˜๋ณด๋‹ค Foundation์— ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ ค๋Š” ์˜๋„
      • Core Foundation vs Foundation
        • ์ฝ”์–ด ํŒŒ์šด๋ฐ์ด์…˜์— ์žˆ๋Š” ๊ธฐ๋Šฅ์€ Foundation์—์„œ ๋ž˜ํ•‘ํ•˜์—ฌ ๊ตฌํ˜„๋˜์–ด์ ธ์žˆ๋‹ค.
        • ๋ณดํ†ต ์•ฑ๊ฐœ๋ฐœ์„ ํ•  ๋•Œ์—๋Š” Foundation์˜ ๊ธฐ๋Šฅ ์—†์ด ๊ฐœ๋ฐœํ•˜๊ธฐ์—๋Š” ์–ด๋ ค์›€์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, Core Foundation์— ๋‚ด์žฅ๋˜์–ด์žˆ๋Š” ๊ธฐ๋Šฅ๋ณด๋‹ค๋Š” Foundation์— ๋‚ด์žฅ๋˜์–ด์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•˜๋Š” ํŽธ์ด๋‹ค.
  • Delegate ํŒจํ„ด๊ณผ ViewController ํƒ€์ž… ๋ชจ๋‘ ์‚ญ์ œ
    • ๋‹ค์Œ STEP๋ฅผ ์ง€๋ ˆ์ง์ž‘ํ•˜์ง€ ๋ง๊ณ  ํ˜„์žฌ STEP์— ์ถฉ์‹คํ•˜์ž.
    • ์‹œ๋„ํ•˜๊ณ  ์‹คํŒจํ•˜๊ณ  ๋Œ์•„๊ฐ€๋Š” ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋ฉฐ ๊ฐœ์„ ํ•ด๋‚˜๊ฐ€๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ง„ํ–‰ํ•˜์ž.
  • Message์˜ ๋„ค์ด๋ฐ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ฐœ์„ 
    • Menu์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ menuList์˜ ํ”„๋กœํผํ‹ฐ ๋‚ด๋ถ€ ํ•˜๋“œ์ฝ”๋”ฉ์„ ๊ฐœ์„ 
  • NumberFormatter๋ฅผ ํ™œ์šฉํ•˜์˜€๋˜ ๋ถ€๋ถ„์„ Double์„ ํ™•์žฅํ•˜์—ฌ ๊ฐœ์„ 
    • String(format:)์„ ํ™œ์šฉํ•˜์—ฌ description์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌ์„ฑ

top


STEP 3 : ๋‹ค์ค‘ ์ฒ˜๋ฆฌ

์€ํ–‰์› ์—ฌ๋Ÿฌ๋ช…์ด ์—…๋ฌด๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

3-1 ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ

1. ๋‹ค์ค‘ ์ฒ˜๋ฆฌ

  • ์—ฌ๋Ÿฌ ์€ํ–‰์›์ด ๋™์‹œ์— ๊ณ ๊ฐ์˜ ์ผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง์„ ๊ณ ๋ฏผํ–ˆ๋‹ค.
  1. global() ํ์— ์€ํ–‰์›์˜ ์ˆ˜ ๋งŒํผ task๋ฅผ ๋งŒ๋“ค๊ณ  ๊ฐ๊ฐ์˜ task์—์„œ ๊ณ ๊ฐ์„ dequeueํ•ด์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹
  2. ํ•˜๋‚˜์˜ while ๊ตฌ๋ฌธ์—์„œ dequeue ํ•ด์ฃผ๊ณ  ๊ณ ๊ฐ์˜ ์€ํ–‰ ์—…๋ฌด์— ๋”ฐ๋ผ ์˜ˆ๊ธˆ ๊ณ ๊ฐ์€ DispatchQueue.global()์— ์„ธ๋งˆํฌ์–ด๋ฅผ ์ด์šฉํ•ด ์€ํ–‰์› ์ˆ˜ == ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์Šค๋ ˆ๋“œ ์ˆ˜ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹
    • DispatchSemaphore์˜ value๋ฅผ 1์ด ์•„๋‹Œ 2๋‚˜ 3์œผ๋กœ ์ค„ ๊ฒฝ์šฐ Race Condition์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๋ฐฉ๋ฒ•์€ ์ ์ ˆํ•˜์ง€ ๋ชปํ•˜๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
    • Banker๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” work() ๋ฉ”์†Œ๋“œ๋Š” ํ˜„์žฌ ๊ณต์œ ์ž์›์— ์ ‘๊ทผํ•˜๊ณ  ์žˆ์ง€ ์•Š์ง€๋งŒ, ์ถ”ํ›„ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๊ฐ€ ๊ณต์œ ์ž์›์— ์ ‘๊ทผํ•˜์ง€ ์•Š์„๊ฑฐ๋ผ๋Š” ๋ณด์žฅ์ด ์—†๋‹ค๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
  • ์ถ”ํ›„ ์€ํ–‰์›์˜ ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์€ํ–‰์› ์ˆ˜ ๋งŒํผ DispatchQueue.global()์— task๋ฅผ ๋งŒ๋“œ๋Š” 1๋ฒˆ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.
    • ์€ํ–‰์› ์ˆ˜ == DispatchQueue์˜ ์ˆ˜

2. ๋Œ€๊ธฐ๋ฒˆํ˜ธ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์—…๋ฌด๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌ

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

3. CustomStringConvertible์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์—ฐ์‚ฐํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉ

  • Banking์˜ ๊ฒฝ์šฐ rawValue๋ฅผ String์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํ˜•ํƒœ์ธ๋ฐ, ์ด ๋ถ€๋ถ„์„ ์€ํ–‰์›์ด ์–ด๋–ค ์—…๋ฌด๋ฅผ ์ฒ˜๋ฆฌํ–ˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ ค๋Š” ์˜๋„๋กœ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ํ”„๋กœํ† ์ฝœ ์ฑ„ํƒ๊ณผ ์—ฐ์‚ฐํ”„๋กœํผํ‹ฐ ์ค‘์— ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ํ™œ์šฉํ•  ์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • CustomStringConvertible์˜ ๊ฒฝ์šฐ ์ธ์Šคํ„ด์Šค๋ฅผ ์›ํ•˜๋Š” ํ˜•ํƒœ์˜ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์ฑ„ํƒํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœํ† ์ฝœ๋กœ ์šฐ๋ฆฌ๊ฐ€ ํ™œ์šฉํ•˜๊ณ ์ž ํ•˜์˜€๋˜ ๋ถ€๋ถ„์ด๋ž‘์€ ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ description์ด๋ผ๋Š” ์—ฐ์‚ฐํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ rawValue๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋‹ค.

3-2 ์˜๋ฌธ์ 

DispatchSemaphore์˜ value๊ฐ€ 1 ์ด์ƒ์ด๋ผ๋ฉด Race Condition์ด ๋ฌด์กฐ๊ฑด ๋ฐœ์ƒํ• ๊นŒ?

  • ์ฒ˜์Œ์— while๋ฌธ ์•ˆ์— DispatchQueue๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  DispatchSemaphore์˜ value๋ฅผ 3์œผ๋กœ ์ฃผ์–ด 3๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์—ฌ๋Ÿฌ๋ฒˆ ๋Œ๋ ค๋„ Race Condition์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜๋‹ค.
  • ์€ํ–‰์›์˜ ์ˆ˜(DispatchSemaphore value)์™€ ๊ณ ๊ฐ์˜ ์ˆ˜๋ฅผ ๋Š˜๋ ค์ฃผ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์•˜๋”๋‹ˆ Race Condition์ด ๋ฐœ์ƒํ•˜์˜€๋‹ค.
    • ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ฉด์„œ ์•Œ๊ฒŒ๋œ ๋ถ€๋ถ„์€ Banker์˜ work() ๋ฉ”์†Œ๋“œ๊ฐ€ ๊ณต์œ ์ž์›์— ์ ‘๊ทผํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์ด์˜€๋‹ค. ํ”„๋กœํผํ‹ฐ count๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ๊ทธ count์— ์ ‘๊ทผํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋”๋‹ˆ Race Condition์ด ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
  • ์ด ์˜๋ฌธ์ ์„ ํ’€๋ฉด์„œ ๊ฒฐ๊ตญ Semaphore์˜ value๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ์ฃผ๋Š” ๊ฒƒ์€ ๊ณต์œ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด Thread-safeํ•˜์ง€ ์•Š์€ ๊ฒƒ์ด๊ณ , ๋”ฐ๋ผ์„œ ์€ํ–‰์›์˜ ์ˆ˜๋ฅผ DispatchSemaphore์˜ value์— ๋งž์ถฐ ์„ค๊ณ„๋ฅผ ํ•˜๋Š” ๊ฒƒ์€ ์ ์ ˆํ•˜์ง€ ๋ชปํ•˜๋‹ค๋Š” ๊ฒฐ๋ก ์ด ๋‚ฌ๋‹ค.

3-3 Truoble Shooting

๊ตฌ์กฐ์ฒด ํ”„๋กœํผํ‹ฐ๋Š” ํด๋กœ์ € ๋‚ด๋ถ€์—์„œ ์™œ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š”๊ฐ€?

  • ์ƒํ™ฉ ํ”„๋กœ์ ํŠธ์—์„œ ย Bank ํƒ€์ž…์€ย ๊ตฌ์กฐ์ฒด์ด๊ณ , numberOfCustomers ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์€ํ–‰์›์ด ์ผ์„ ํ•  ๋•Œ, ์ฒ˜๋ฆฌํ•œ ๊ณ ๊ฐ์˜ ์ˆ˜๋ฅผย Dispatch.global().asyncย ํด๋กœ์ € ๋‚ด์—์„œ ์นด์šดํŠธ(numberOfCustomers) ํ•ด์ฃผ๋„๋ก ํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.
  • ์ด์œ  Escaping closure์˜ ๊ฒฝ์šฐ ๊ตฌ์กฐ์ฒด์—์„œ๋Š” ์บก์ณ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
// ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ์˜ˆ์‹œ
struct SomeStruct {
    var num = 0
    
    private mutating func test() {
        let closure = { // Escaping closure captures mutating 'self' parameter
            self.num += 1
        }
        closure()
    }
}
  • Escaping closure์˜ ๊ฒฝ์šฐ ๊ตฌ์กฐ์ฒด์—์„œ๋Š” ์บก์ณ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

    class์™€ ๊ฐ™์€ ์ฐธ์กฐ ํƒ€์ž…์ด ์•„๋‹Œ Struct, enum๊ณผ ๊ฐ™์€ ๊ฐ’ํƒ€์ž…์—์„œ๋Š” mutating reference์˜ ์บก์ณ๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— self ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅ ํ•˜๋‹ค.

  • ํ•ด๊ฒฐ Bank ํƒ€์ž…์„ ํด๋ž˜์Šค๋กœ ๋ฐ”๊ฟ”์ฃผ์—ˆ๋‹ค.

3-4 ๋ฐฐ์šด ๊ฐœ๋…

  • ๋™๊ธฐ(Synchronous)์™€ ๋น„๋™๊ธฐ(Asynchronous)์˜ ์ดํ•ด
  • ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋…์˜ ์ดํ•ด
  • ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•œ ๊ธฐ๋ฐ˜๊ธฐ์ˆ (GCD, Operation) ๋“ฑ์˜ ์ดํ•ด
  • ์Šค๋ ˆ๋“œ(Thread) ๊ฐœ๋…์— ๋Œ€ํ•œ ์ดํ•ด
  • GCD๋ฅผ ํ™œ์šฉํ•œ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ตฌํ˜„
  • ๋™๊ธฐ(Synchronous)์™€ ๋น„๋™๊ธฐ(Asynchronous) ๋™์ž‘์˜ ๊ตฌํ˜„ ๋ฐ ์ ์šฉ

3-5 PR ํ›„ ๊ฐœ์„ ์‚ฌํ•ญ

  • Bank ํƒ€์ž… ๋ฆฌํŒฉํ† ๋ง
    • ์€ํ–‰์› ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ”„๋กœํผํ‹ฐ๋ช… number๋ฅผ count๋กœ ์ˆ˜์ •
    • Bankํƒ€์ž…์„ class๊ฐ€ ์•„๋‹Œ struct๋กœ ์ˆ˜์ •
    • workBanker()ย ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์— while๋ฌธ์„ while let์œผ๋กœ ์ˆ˜์ •
  • Banker ํƒ€์ž…์˜ย workSpeed()ย ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ฑฐ
  • LinketList์˜ย removeFirst()ย ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€๋ฅผ Thread-Safeํ•˜๊ฒŒ ๊ฐœ์„ 
    • Thread Safe
      • ๊ธฐ์กด ๋กœ์ง์€ ์€ํ–‰์› ์ˆ˜๋งŒํผ global() ํ์— Task๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์ด์—ฌ์„œ ํ•˜๋‚˜์˜ ๊ณ ๊ฐ ํ์— ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์ ‘๊ทผํ•ดย Race Condition์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ.
      • ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ๊ณ ๊ฐ ํ์— ์ ‘๊ทผํ•ด๋„ LinkedList์—์„œ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋กย SerialQueue.sync๋ฅผ ํ™œ์šฉํ•˜์—ฌย Race Condition์„ ํ•ด๊ฒฐ

top


STEP 4 : UI ๊ตฌํ˜„

์ฝ˜์†”์•ฑ์„ UI์•ฑ์œผ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

UI ๊ตฌ์„ฑ ์„ค๊ณ„

4-1 ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ

  • ํ™”๋ฉด ์ „์ฒด๋ฅผ ์Šคํƒ๋ทฐ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
  • ๋™์ผํ•œ ๊ตฌ์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ทฐ๋ฅผ Custom View๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • ๋™์ผํ•œ ์š”์†Œ๊ฐ€ ์žˆ๋Š” ๋ทฐ๋ฅผ ์ปค์Šคํ…€ํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„
  • ๋ทฐ๋ฅผ ๊ทธ๋ฆด ๋•Œ main Thread์—์„œ ๋ฐ”๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • delegate๋ฅผ ํ™œ์šฉํ•˜์—ฌ ViewController๊ฐ€ ๋ทฐ๋ฅผ ๊ทธ๋ฆฌ๋Š” ์‹œ์ ์— DispatchQueue.main.async๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ทฐ๋ฅผ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„
  • ๊ฐ์ข… ์˜ˆ์™ธ์‚ฌํ•ญ์— ๋Œ€ํ•ด ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ์–ด๋–ค ๋กœ์ง์„ ์ถ”๊ฐ€ํ•ด์•ผํ•˜๋Š”์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • ๊ณ ๊ฐ 10๋ช… ์ถ”๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญ์‹œ ์€ํ–‰์ด ์ผ์„ ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ๊ณ ๊ฐ๋งŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋กœ์ง ์ถ”๊ฐ€
    • ๊ณ ๊ฐ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ๋จผ์ € ์ผ์ด ๋๋‚˜์„œ ์‚ฌ๋ผ์ง„ Thread(์€ํ–‰์›)๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‹ค์‹œ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก DispatchQueue๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋กœ์ง ์ถ”๊ฐ€ (ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„ ํ™œ์šฉ)

4-2 ์˜๋ฌธ์ 

  • Bool ํƒ€์ž… ๋„ค์ด๋ฐ์„ ํ• ๋•Œ ๋ถ€์ •๋ฌธ์„ ์‚ฌ์šฉํ•ด๋„ ๋ ๊นŒ?

    • Bool ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค ๋•Œ ๋ถ€์ •๋ฌธ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์•„๋ž˜ guard ๊ตฌ๋ฌธ์„ ํ•œ๊ตญ๋ง๋กœ ํ‘œํ˜„ํ•˜๋ฉด ํƒ€์ด๋จธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒ ์‹œ์ผœ๋ผ ๋ผ๊ณ  ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

      • ๋‹ค์‹œ ๋งํ•ด ํƒ€์ด๋จธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒ์‹œ์ผœ๋ผ๋กœ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ƒ๊ฐํ•ด์•ผํ•œ๋‹ค.
    • ํ•˜์ง€๋งŒ ์ฝ”๋“œ๋Š” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

      // ํƒ€์ด๋จธ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ guard ๊ตฌ๋ฌธ์—์„œ ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•จ.
      func open() {
          let isNotWorking = timer == nil
          guard isNotWorking else {
              return
          }
          startTimer()
          
          // ... 
      }
    • Bool ํƒ€์ž… ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค ๋•Œ ๋ถ€์ •๋ฌธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋’ค์— false ๊ตฌ๋ฌธ์ด ์ถ”๊ฐ€๋œ๋‹ค.

      // ํƒ€์ด๋จธ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ guard ๊ตฌ๋ฌธ์—์„œ ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•จ.
      func open() {
          let isWorking = timer != nil
          guard isWorking == false else {
              return
          }
          startTimer()
          
          // ... 
      }
    • ํ”„๋กœํผํ‹ฐ๋กœ ํ•œ๋ฒˆ์— ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์€๊ฑด์ง€ ์•„๋‹ˆ๋ฉด false๋ฌธ์ด๋ผ๋„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ฝ๊ธฐ ์ˆ˜์›”ํ•˜๋„๋ก ๊ตฌ์„ฑํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š”๊ฒŒ ๋งž๋Š”๊ฑด์ง€ ์˜๋ฌธ์ด๋‹ค.

  • DispatchQueue๋Š” ์ž‘์—…ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ์ค‘๊ฐ„์— ์ค‘์ง€์‹œํ‚ฌ ์ˆ˜ ์žˆ์„๊นŒ?

    • cancel ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋”๋ผ๋„ ์ž‘์—…์ด ์ž‘์—… ์ค‘์ด๋ผ๋ฉด ์ค‘์ง€์‹œํ‚ฌ ์ˆ˜ ์—†๋‹ค.
    • ์šฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•˜์ง€๋งŒ GCD๊ฐ€ ์ž‘์—…์„ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ํ•˜๋Š” ๊ฒƒ์€ ํ•  ์ˆ˜๋Š” ์—†๋‹ค.
    • Operation Queue๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘์—… ์ค‘์ธ ์ž‘์—…์„ ์ค‘์ง€ ํ•  ์ˆ˜ ์žˆ๋‹ค. [์ฐธ๊ณ  ๋งํฌ]
  • Custom View ํด๋ž˜์Šค ๋‚ด๋ถ€์— ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ ธ๋„ ๋˜๋Š”๊ฐ€?

    • ํ•„์š”ํ•˜๋‹ค๋ฉด ์‚ฌ์šฉํ•ด๋„ ๋ฌด๊ด€ํ•˜๋‹ค.
    • ํŠน์ • ๋ทฐ๋ฅผ ์ฐพ์„ ๋•Œ Int, String์ฒ˜๋Ÿผ ์ค‘๋ณต๋œ ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ ๋ทฐ๋ฅผ ์ฐพ์•„์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค.
    • UUID๋ฅผ ํ™œ์šฉํ•˜๋Š” ํ™œ์šฉํ•˜๋ฉด ๊ณ ์œ ํ•œ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.

4-3 Trouble Shooting

1. ๋ทฐ์˜ ์š”์†Œ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ

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

2. ๋ฉˆ์ถ”์ง€ ์•Š๋Š” ํƒ€์ด๋จธ

  • ์ƒํ™ฉ ๊ณ ๊ฐ ์ถ”๊ฐ€๋ฒ„ํŠผ์„ ์—ฌ๋Ÿฌ๋ฒˆ ํด๋ฆญํ•˜๊ณ  ์ดˆ๊ธฐํ™”๋ฅผ ๋ˆ„๋ฅด๊ฒŒ ๋˜๋ฉด ํƒ€์ด๋จธ๊ฐ€ ๋ฉˆ์ถ”์ง€ ์•Š์•˜๋‹ค.
  • https://i.imgur.com/fvZWEq1.gif
  • ์ด์œ  ํƒ€์ด๋จธ๊ฐ€ ์ถ”๊ฐ€๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๊ณ„์† ์ถ”๊ฐ€๋˜๋ฉด์„œ ์ถ”๊ฐ€๋œ ํƒ€์ด๋จธ๊ฐ€ ๋๋‚˜์ง€ ์•Š๊ณ  ๊ณ„์† ์‹คํ–‰๋˜๋Š” ๋“ฏ ํ–ˆ๋‹ค.
  • ํ•ด๊ฒฐ ์ดˆ๊ธฐํ™” ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ, ๋Œ€๊ธฐ์ค‘์ธ ๊ณ ๊ฐ์ด ์—†์„ ๋•Œ ํƒ€์ด๋จธ๋ฅผ ๋ฉˆ์ถ”๋ฉด์„œ ํƒ€์ด๋จธ์— nil์„ ๋Œ€์ž…ํ•ด์ฃผ์—ˆ๊ณ , ํƒ€์ด๋จธ๊ฐ€ ์ž‘๋™์ค‘์—๋Š” ํƒ€์ด๋จธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋‹ˆ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.
  • https://i.imgur.com/VsvkGMM.gif

4-4 ๋ฐฐ์šด ๊ฐœ๋…

  • ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ค‘ UI ์š”์†Œ ์—…๋ฐ์ดํŠธ์˜ ์ฃผ์˜์  ์ดํ•ด
  • ์ปค์Šคํ…€ ๋ทฐ ๊ตฌํ˜„
  • ์Šคํƒ๋ทฐ ํ™œ์šฉ
  • ์ฝ”๋“œ๋กœ UI ๊ตฌ์„ฑ(์˜คํ† ๋ ˆ์ด์•„์›ƒ)
  • ํƒ€์ด๋จธ ํ™œ์šฉ๋ฐฉ๋ฒ•๊ณผ Run Loop

top

About

๐Ÿฆ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ™œ์šฉํ•˜์—ฌ ์€ํ–‰ ์ฐฝ๊ตฌ ์—…๋ฌด ์Šค์ผ€์ค„์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ์•ฑ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Swift 100.0%