Bibi's DevLog ๐Ÿค“๐ŸŽ

[Swift] delay : ์ง€์—ฐ์‹œ๊ฐ„ ๋‘๊ณ  ์ฝ”๋“œ (๋ฐ˜๋ณต) ์‹คํ–‰ํ•˜๊ธฐ - Timer, asyncAfter ๋ณธ๋ฌธ

๐Ÿ“ฑ๐ŸŽ iOS/๐Ÿ•Š Swift

[Swift] delay : ์ง€์—ฐ์‹œ๊ฐ„ ๋‘๊ณ  ์ฝ”๋“œ (๋ฐ˜๋ณต) ์‹คํ–‰ํ•˜๊ธฐ - Timer, asyncAfter

๋น„๋น„ bibi 2022. 12. 2. 23:10

์ฐธ๊ณ ํ•œ ๋ฌธ์„œ

The ultimate guide to Timer

Apple Developer Documentation

Why would a scheduledTimer fire properly when setup outside a block, but not within a block?

Swift์—์„œ ์ง€์—ฐ์‹œ๊ฐ„์„ ๋‘๊ณ  ์ฝ”๋“œ๋ฅผ (๋ฐ˜๋ณต)์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋Š”๋ฐ,

Timer์™€ DispatchQueue.main.asyncAfter ์ด๋‹ค.

Note:
Before I start, I want to make it clear that there is a significant energy cost to using timers. Weโ€™ll look at ways to mitigate this, but broadly any kind of timer must wake the system from its idle state in order to trigger work, and that has an associated energy cost.
ํƒ€์ด๋จธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ƒ๋‹นํ•œ ์—๋„ˆ์ง€๋ฅผ ์†Œ๋ชจํ•˜๋Š” ์ž‘์—…์ž„์„ ์•Œ์•„์•ผ ํ•œ๋‹ค. ๋ฌผ๋ก  ์™„ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

1. Timer

  • ๊ธฐ๋ณธ์ ์ธ ๋ฐ˜๋ณต ํƒ€์ด๋จธ ์‚ฌ์šฉ์€ Timer.scheduledTimer ๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค.

      // ์…€๋ ‰ํ„ฐ๋กœ ๋„˜๊ธฐ๊ธฐ - ํƒ€์ด๋จธ๋ฅผ ๋ณ€์ˆ˜๋กœ ๋นผ์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹๋‹ค
      let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
      @objc func fireTimer() {
          print("Timer fired!")
      }
    
      // ๋˜๋Š” ํด๋กœ์ €๋กœ ๋ฐ˜๋ณต์ˆ˜ํ–‰ ๋™์ž‘์„ ๋„˜๊ธธ ์ˆ˜๋„ ์žˆ์Œ - inline์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹๋‹ค
      let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
          print("Timer fired!")
      }
    • ํƒ€์ด๋จธ๋ฅผ ํ”„๋กœํผํ‹ฐ๋กœ ๋งŒ๋“ค์–ด ๋‘๋ฉด ๋‚˜์ค‘์— ์ข…๋ฃŒํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.
  • ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๋Š” ํƒ€์ด๋จธ - repeates ๋ฅผ false๋กœ ํ•œ๋‹ค.

    • ์ž๋™์œผ๋กœ ์Šค์Šค๋กœ invalidate๋œ๋‹ค.

      let timer1 = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: false)
      
      let timer2 = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { timer in
        print("Timer fired!")
      }
  • ํƒ€์ด๋จธ ์ข…๋ฃŒ : invalidate() ๋ฅผ ์‚ฌ์šฉ

      var runCount = 0
    
      Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
          print("Timer fired!")
          runCount += 1
    
          if runCount == 3 {
              timer.invalidate()
          }
      }
  • userInfo ์ธ์ž์— ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•ด ํƒ€์ด๋จธ๋ฅผ ๋ฐœ๋™ํ•œ ๋งฅ๋ฝ์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. (Any? ํƒ€์ž…)

      let context = ["user": "@twostraws"]
      Timer.scheduledTimer(timeInterval: 1.0, target: self, 
                                              selector: #selector(fireTimer), userInfo: context, repeats: true)
    
      @objc func fireTimer(timer: Timer) {
          guard let context = timer.userInfo as? [String: String] else { return }
          let user = context["user", default: "Anonymous"]
    
          print("Timer fired by \(user)!")
          runCount += 1
    
          if runCount == 3 {
              timer.invalidate()
          }
      }
  • tolerance(ํ—ˆ์šฉ ์˜ค์ฐจ)

    • ์‹œ์Šคํ…œ์ด ์›๋ž˜ ์ง€์ •ํ•œ ์‹œ๊ฐ„๊ณผ ํ—ˆ์šฉ ์˜ค์ฐจ ์‚ฌ์ด์˜ ์–ด๋Š ์‹œ์ ์—๋“  ํƒ€์ด๋จธ๋ฅผ ๋ฐœ๋™(trigger)ํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธ

    • ํƒ€์ด๋จธ๊ฐ€ ์†Œ๋ชจํ•˜๋Š” ์—๋„ˆ์ง€๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด๋‹ค.

      • ์‹œ์Šคํ…œ์€ ์–ธ์ œ๋‚˜ ์ž๋™์ ์œผ๋กœ ์•ฝ๊ฐ„์˜ ํ—ˆ์šฉ์˜ค์ฐจ๋ฅผ ๋‘”๋‹ค.
    • tolerance๋ฅผ ์ง€์ •ํ•˜๋”๋ผ๋„ ์ ˆ๋Œ€๋กœ ์ง€์ • ์‹œ๊ฐ„ ์ด์ „์— ํƒ€์ด๋จธ๋ฅผ ๋ฐœ๋™ํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

    • tolerance๋ฅผ ์ง€์ •ํ•˜๋”๋ผ๋„ ํƒ€์ด๋จธ๊ฐ€ drift๋˜์ง„ ์•Š๋Š”๋‹ค (=๋‹ค์Œ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ๋” ๋นจ๋ฆฌ ๋ฐœ๋™๋˜์ง„ ์•Š๋Š”๋‹ค)

      let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
      timer.tolerance = 0.2 // default๊ฐ’์€ 0์ž„.

      As an example, consider a timer that was asked to execute every 1 second with a 0.5 second tolerance. It might run like this:

      After 1.0 seconds the timer fires.
      After 2.4 seconds the timer fires again. Itโ€™s 0.4 seconds late, but thatโ€™s still within our tolerance.
      After 3.1 seconds the timer fires again. This is only 0.7 seconds after our previous fire event, but each fire date is calculated from the original regardless of tolerance.
      After 4.5 seconds the timer fires again.
      And so onโ€ฆ

  • runloop์™€ ํ•จ๊ป˜ ์ž‘์—…ํ•˜๊ธฐ

    • โœ… ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ์ค‘์—๋Š” Timer๊ฐ€ ๋ฐœ๋™๋˜์ง€ ์•Š๋Š”๋‹ค.

    • ์™œ? ์šฐ๋ฆฌ๋Š” ์•”๋ฌต์ ์œผ๋กœ Timer๋ฅผ ๋Ÿฐ๋ฃจํ”„์˜ defaultRunLoopMode์—์„œ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Œ

    • ์ด๊ฒƒ์€ ์•ฑ์˜ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ์œ ํšจํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž-UI ์ƒํ˜ธ์ž‘์šฉ์ด ์ผ์–ด๋‚˜๋Š” ์ค‘์—๋Š” ์ผ์‹œ์ค‘์ง€๋œ๋‹ค. ์ƒํ˜ธ์ž‘์šฉ์ด ๋๋‚˜๋ฉด ์žฌ๊ฐœ๋œ๋‹ค.

    • ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ์ง์ ‘ ์„ ํƒํ•œ ๋Ÿฐ๋ฃจํ”„์— ํƒ€์ด๋จธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

      • ํƒ€์ด๋จธ๊ฐ€ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด ๋Ÿฐ๋ฃจํ”„๋ฅผ ๊ฐ–์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ.
      • ํƒ€์ด๋จธ๋Š” ๋ฐ˜๋“œ์‹œ ๋Ÿฐ๋ฃจํ”„๋ฅผ ๊ฐ€์ ธ์•ผ ํ•จ. ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋Š” ํ•˜๋‚˜์˜ ๋Ÿฐ๋ฃจํ”„๋ฅผ ๊ฐ€์ง€์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„์˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๋Š” ์ง์ ‘ ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „์—๋Š” ๋Ÿฐ๋ฃจํ”„๋ฅผ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค. - ์ฐธ๊ณ 
      • ํƒ€์ด๋จธ๋Š” ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ๋Ÿฐ๋ฃจํ”„์—๋งŒ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ. ๋‹จ, ํ•ด๋‹น ๋Ÿฐ๋ฃจํ”„์˜ ์—ฌ๋Ÿฌ ๋Ÿฐ๋ฃจํ”„๋ชจ๋“œ์—๋Š” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • .common : UI ์‚ฌ์šฉ ์ค‘์—๋„ ํƒ€์ด๋จธ๊ฐ€ ๋ฐœ๋™๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ๋Š” ๋Ÿฐ๋ฃจํ”„ ๋ชจ๋“œ.

      // ํƒ€์ด๋จธ ๋™์ž‘์ด ์•ˆ๋  ์‹œ, ์ง์ ‘ ๋Ÿฐ๋ฃจํ”„์— ํƒ€์ด๋จธ๋ฅผ ๋”ํ•ด ์ค€๋‹ค.
      let context = ["user": "@twostraws"]
      let timer = Timer(timeInterval: 1.0, target: self, selector: #selector(fireTimer), userInfo: context, repeats: true)
      RunLoop.current.add(timer, forMode: .common)
      
      // ๋˜๋Š” main์Šค๋ ˆ๋“œ๋กœ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค
      DispatchQueue.main.async {
        self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true)
      }
  • ํ™”๋ฉด ๋ณ€ํ™”์— ํƒ€์ด๋จธ ๋™๊ธฐํ™”ํ•˜๊ธฐ

    • CADisplayLink ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์•„๋ž˜๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ์˜ˆ์ œ. ( ์ฐธ๊ณ  )

      let displayLink = CADisplayLink(target: self, selector: #selector(fireTimer))
      displayLink.add(to: .current, forMode: .default)
    • ํƒ€์ด๋จธ ๋ฐœ๋™ ์‹œ, UI๊ฐ€ ์‚ฌ์šฉ์ค‘์ž„์—๋„ ํ™”๋ฉด๊ณผ ์—ฐ๊ฒฐ๋œ ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐœ๋™์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด .common ์„ ์‚ฌ์šฉํ•˜๋ผ.

๋Ÿฐ๋ฃจํ”„ RunLoop

Apple Developer Documentation

Run Loops

RunLoop ๋Ÿฐ๋ฃจํ”„๋ž€??

  • ๋Ÿฐ๋ฃจํ”„๋ž€ ์Šค๋ ˆ๋“œ์™€ ์—ฐ๊ด€๋œ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฌผ์˜ ์ผ๋ถ€์ด๋‹ค.
  • ๋Ÿฐ๋ฃจํ”„๋Š” ์ž‘์—…์„ ์˜ˆ์•ฝ(schedule)ํ•˜๊ณ , ๋“ค์–ด์˜ค๋Š” ์ด๋ฒคํŠธ์˜ ์ˆ˜์‹ ์„ ์กฐ์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฃจํ”„์ด๋‹ค.
  • ๋Ÿฐ๋ฃจํ”„์˜ ๋ชฉ์ ์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์ผํ•ด์•ผ ํ•  ๋•Œ๋Š” ์ผํ•˜๊ณ , ์ผ์ด ์—†์„ ๋•Œ๋Š” ์‰ฌ๋„๋ก ํ•˜๋Š” ๊ฒƒ!
  • ๋Ÿฐ๋ฃจํ”„ ๊ด€๋ฆฌ๋Š” ์™„์ „ ์ž๋™์ด ์•„๋‹˜. ํ•„์š”ํ•  ๋•Œ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์ง์ ‘ ์กฐ์ •ํ•ด์ค˜์•ผ ํ•จ.
    • Cocoa์™€ Core Foundation์€ ๋Ÿฐ๋ฃจํ”„ ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ํฌํ•จํ•ด ๊ฐ ์Šค๋ ˆ๋“œ์—๋Š” ๋ชจ๋‘ ์—ฐ๊ด€๋œ ๋Ÿฐ๋ฃจํ”„ ๊ฐ์ฒด๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์กด์žฌํ•œ๋‹ค.
    • ๋”ฐ๋ผ์„œ ๋Ÿฐ๋ฃจํ”„ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•  ์ผ์€ ์—†๋‹ค.
  • ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์˜ ๋Ÿฐ๋ฃจํ”„๋Š” ์ž๋™์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.
    • ์•ฑ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•ฑ ์‹œ์ž‘ ํ”„๋กœ์„ธ์Šค์˜ ์ผํ™˜์œผ๋กœ ์‹คํ–‰ํ•ด ์ฃผ๋Š” ๊ฒƒ์ž„.
  • ๋ฉ”์ธ์ด ์•„๋‹Œ ๋ณด์กฐ ์Šค๋ ˆ๋“œ๋“ค์€ ๋Ÿฐ๋ฃจํ”„๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ โ€˜์‹คํ–‰'ํ•ด ์ฃผ์–ด์•ผ ๋™์ž‘ํ•œ๋‹ค.

โœ… Command Line Tool(macOS) ํ”„๋กœ์ ํŠธ์—์„œ ํƒ€์ด๋จธ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ์ด์œ 

โ†’ CLT์—์„œ๋Š” ๋ฉ”์ธ ๋Ÿฐ๋ฃจํ”„๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹คํ–‰๋˜์ง€ ์•Š์Œ. ์•ฑ ํ”„๋ ˆ์ž„์›Œํฌ๋งŒ์ด ๋ฉ”์ธ ๋Ÿฐ๋ฃจํ”„๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹คํ–‰ ์ƒํƒœ๋กœ ๋งŒ๋“ค์–ด ์ค„ ๋ฟ์ž„. CLT์—์„œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋Ÿฐ๋ฃจํ”„์˜ ์‹คํ–‰์„ ํ•ด์ค˜์•ผ ํ•จ.

  • ํƒ€์ด๋จธ๋Š” ๊ทธ๊ฒƒ์ด ์ž‘๋™๋˜๊ธฐ ์œ„ํ•œ ๋Ÿฐ๋ฃจํ”„๊ฐ€ ํ•„์š”ํ•œ๋ฐ, CLI ํ™˜๊ฒฝ์€ ๋Ÿฐ๋ฃจํ”„๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ์ƒํƒœ์ด๋‹ค. ๋ช…์‹œ์ ์œผ๋กœ ์‹คํ–‰์ด ํ•„์š”ํ•จ
    • iOS App ํ”„๋กœ์ ํŠธ๋Š” ์•ฑ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์˜ ๋Ÿฐ๋ฃจํ”„๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹คํ–‰ํ•ด ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์‹คํ–‰์ด ํ•„์š”ํ•˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์ž„.

๋ฐฉ๋ฒ•1 - ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ ๋ช…์‹œ

  • ์‹œ์ž‘ : CFRunLoopRun()
  • ์ข…๋ฃŒ : CFRunLoopStop()
  • ํ˜„์žฌ ๋Ÿฐ๋ฃจํ”„ ์–ป๊ธฐ : CFRunLoopGetCurrent()
var count = 0

let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { t in
    count += 1
    print(count)
    if count >= 5 {
        t.invalidate()
        CFRunLoopStop(CFRunLoopGetCurrent())
    }
}
// run ์„ ์–ธ ์ด์ „์— ์„ ์–ธํ•œ ํƒ€์ด๋จธ๋“ค๋งŒ ๋™์ž‘ํ•œ๋‹ค.
CFRunLoopRun()

๋ฐฉ๋ฒ•2 - run(until:) ์‚ฌ์šฉ

RunLoop์˜ run ๋ฉ”์„œ๋“œ ์ค‘..

  • run() ์€ ๋ฌดํ•œ๋ฐ˜๋ณตํ•  ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ์“ฐ์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค. RunLoop๋Š” ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฐ๋กœ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‹คํ–‰ ํ›„ ์ž๋™์œผ๋กœ ์ข…๋ฃŒ๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • run(until:) : ์ง€์ • ์‹œ๊ฐ„๊นŒ์ง€ ์‹คํ–‰. ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ.
var count = 0

let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { t in
    count += 1
    print(count)
    if count >= 5 {
        t.invalidate()
    }
}
while count < 5 {
    RunLoop.current.run(until: Date().addingTimeInterval(0.1))
}

2. DispatchQueue.main.asyncAfter(deadline:execute:)

Apple Developer Documentation

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    print("Timer fired!")
}

ํŠน์ • ์‹œ์ ์— ์ž‘์—… ๋‚ด์šฉ์˜ ์‹คํ–‰์„ ์˜ˆ์•ฝํ•ด ๋‘๊ณ , ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•จ.

  • ๋ฐ˜๋ณต์ด ์•„๋‹Œ ๋‹จ์ˆœ ์ง€์—ฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์œ ์šฉ.

    • ๋น„๋™๊ธฐ๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ, asyncAfter๋ฅผ ๋ฐ˜๋ณต์‹คํ–‰ํ•ด๋„ ์ง€์ • ์‹œ๊ฐ„ ํ›„์— ๋ฐ˜๋ณต๋˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์ฆ‰์‹œ ๋ฐ˜๋ณต๋จ

    • ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•ด๋„ 1์ดˆ๋งˆ๋‹ค ๋ฐ˜๋ณต๋˜์ง€ ์•Š๋Š”๋‹ค.. ์ฃผ์˜

      var isRunning = true
      var loop = 0
      while isRunning {
        print(Thread.current.isMainThread)
        print("asyncafter")
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
            print("asyncAfter!")
        }
        loop += 1
        if loop == 10 {
            isRunning = false
        }
      }
  • Timer๋ณด๋‹ค ๊ฐ„๋‹จํ•˜๋‹ค.

  • GCD๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

DispatchSource.makeTimerSource(queue:)

  • ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ์—์„œ ์‹คํ–‰๋˜๋Š” ํƒ€์ด๋จธ
  • ๋Ÿฐ๋ฃจํ”„๋ฅผ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š์Œ
var timer: DispatchSourceTimer!

private func startTimer() {
    let queue = DispatchQueue(label: "com.domain.app.timer")
    timer = DispatchSource.makeTimerSource(queue: queue)
    timer.setEventHandler { [weak self] in
        // do something
    }
    timer.schedule(deadline: .now(), repeating: 1.0)
    timer.resume()
}