iOS 응용 (swift)

[iOS - swift] DispatchQueue 작업 취소, 작업 예약 방법 (DispatchSourceTimer, makeTimerSource, 일시 정지 타이머)

jake-kim 2024. 10. 7. 01:48

DispatchQueue 작업 취소, 예약 방법

  • 5초 후에 특정 작업을 수행하고 싶은 경우?
    • 보통은 DispatchQueue 사용
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
    // some task...
}
  • 5초 후에 특정 작업을 수행하려고 하지만, 중간에 버튼을 누르면 이 작업을 취소하고 싶은 경우?
    • DispatchSourceTimer 사용

DispatchSourceTimer 개념

https://developer.apple.com/documentation/dispatch/dispatchsourcetimer

  • 타이머를 설정해놓고 특정 작업을 setEventHandler 클로저로 실행시킬 수 있는 기능
  • 이것을 사용하면 작업을 등록해놓고 cancel, pause 모두 다 가능

DispatchSourceTimer 사용 방법

  • 인스턴스 하나를 두고 cancel(), pause()할 수 있도록 전역으로 선언
class ViewController: UIViewController {
    private let dispatchSourceTimer: DispatchSourceTimer = DispatchSource.makeTimerSource(queue: DispatchQueue.main)   
}
  • viewDidLoad()가 호출되면 작업을 예약
    • schedule(deadline:)을 통해 몇초 후에 setEventHandler를 동작시킬지 예약
    • setCancelHandler를 통해 취소되었을때 어떤 행동을 할것인지 클로저로 관리
    • resume()을 통해 시작
override func viewDidLoad() {
    super.viewDidLoad()

    runDispatchSourceTimer()
}

func runDispatchSourceTimer() {
    dispatchSourceTimer.schedule(deadline: .now() + 5)

    dispatchSourceTimer.setEventHandler {
        print("event!")
    }

    dispatchSourceTimer.setCancelHandler {
        print("cancel!")
    }

    dispatchSourceTimer.resume()
}
  • 주의사항)
    • 5초 후에 setEventHandler가 실행된 후에도 cancel()을 호출하면 setCancelHandler가 실행
  • cancel() 메서드를 호출하면 작업이 취소
@objc
private func tap() {
    dispatchSourceTimer.cancel()
}
  • 기타) schedule(deadline:)은 1회 수행이지만 schedule(deadline:repeating:leeway:)와 같은것을 사용하면 반복적으로 실행가능

https://developer.apple.com/documentation/dispatch/dispatchsourcetimer

 

* 전체 코드)

import UIKit

class ViewController: UIViewController {
    private let button = {
        let btn = UIButton(type: .system)
        btn.setTitle("button", for: .normal)
        btn.setTitleColor(.blue, for: .normal)
        btn.setTitleColor(.systemBlue, for: [.normal, .highlighted])
        btn.translatesAutoresizingMaskIntoConstraints = false
        return btn
    }()
    
    private let dispatchSourceTimer: DispatchSourceTimer = DispatchSource.makeTimerSource(queue: DispatchQueue.main)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        addButtonLayoutAndEvent()
        runDispatchSourceTimer()
    }
    
    func addButtonLayoutAndEvent() {
        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        ])
        button.addTarget(self, action: #selector(tap), for: .touchUpInside)
    }
    
    func runDispatchSourceTimer() {
        dispatchSourceTimer.schedule(deadline: .now() + 5)
        
        dispatchSourceTimer.setEventHandler {
            print("event!")
        }
        
        dispatchSourceTimer.setCancelHandler {
            print("cancel!")
        }
        
        dispatchSourceTimer.resume()
    }
    
    @objc
    private func tap() {
        dispatchSourceTimer.cancel()
    }
}

 

* 참고

- https://developer.apple.com/documentation/dispatch/dispatchsourcetimer