(swift) BASIC_09. DispatchSourceTimer, UIView Animation

Reading time ~1 minute

[swift] BASIC_09. DispatchSourceTimer, UIView Animation


DispatchSourceTimer

특정 시간이 지난 뒤 이벤트를 발생시킨다거나, 반복적인 주기로 특정 작업을 수행하는 등의 행위를 할 때 사용

swift에서 timer class를 이용하여 타이머를 구현할 수 있지만, pomodoroTimer에서는 DispatchSourceTimer를 이용하여 구현하였다.

var timer: DispatchSourceTimer?

func startTimer() {
    if self.timer == nil {
        self.timer = DispatchSource.makeTimerSource(flags: [], queue: .main) // UI를 수정해야 하므로 .main(ios에서 오직 한 개만 존재하는 스레드)
        self.timer?.schedule(deadline: .now(), repeating: 1)
        self.timer?.setEventHandler(handler: { [ weak self] in
        guard let self = self else { return } // strong reference
        self.currentSeconds -= 1
        
        let hour = self.currentSeconds / 3600
        let minutes = (self.currentSeconds % 3600) / 60
        let seconds = (self.currentSeconds % 3600) % 3600
        self.lblTimer.text = String(format: "%02d:%02d:%02d", hour, minutes, seconds)

        self.progressView.progress = Float(self.currentSecnods) / Float(self.duration)

        if self.currentSeconds <= 0 {
            self.stopTimer()
            AudioServicesPlaySystemSound(1005)
        }
        })
    }
}

func stopTimer() {
    // 일시정지 상태에서 timer에 nil을 대입하면 에러가 난다. 그렇기에 resume() 메서드를 사용해야 한다.
    if self.timerStatus == .pause {
        self.timer?.resum()
    }
    self.timerStatus = .end
    self.timer?.cancel()
    self.timer = nil    // 타이머를 종료할 때 nil을 사용하여 해제시켜야 메모리를 소모하지 않는다.
}

@IBAction func tapStart(_ sender: UIButton) {
        self.duration = Int(self.datePicker.countDownDuration) // 2분 -> 120초와 같이 저장해줌.
//        debugPrint(self.duration)
        
        switch self.timerStatus {
        case .end:
            self.currentSeconds = self.duration
            self.timerStatus = .start
            self.startTimer()
        case .start:
            self.timerStatus = .pause
            self.timer?.suspend()   // 타이머 일시정지
        case .pause:
            self.timerStatus = .start
            self.timer?.resume()
        }
    }




UIView Animation

UIView 클래스는 Animation에서 사용되는 api를 타입 메서드로 제공하고, 이 메서드를 활용하여 비교적 단순한 코드로 애니메이션을 구현하였다.
pomodoroTimer에서 버튼을 hidden으로 구현하지 않고, alpha 값으로 구현하여 자연스럽게 구현하였다.
또한, 타이머가 진행될 때 imageView를 회전시키는 애니메이션을 구현하였다.

enum TimerStatus {
    case start
    case pause
    case end
}

class ViewController: UIViewController {
    func setTimerInfoViewVisible(isHidden: Bool) {
        if isHidden {
            UIView.animate(withDuration: 0.5, animations: {
                self.lblTimer.alpha = 0
                self.progressView.alpha = 0
                self.datePicker.alpha = 1
                self.imgPomodoro.transform = .identity
            })
        } else {
            UIView.animate(withDuration: 0.5, animations: {
                self.lblTimer.alpha = 1
                self.progressView.alpha = 1
                self.datePicker.alpha = 0
            })
        }

        // hidden 사용
//        self.lblTimer.isHidden = isHidden
//        self.progressView.isHidden = isHidden
        
        self.btnStart.isSelected = !isHidden
        self.btnCancel.isEnabled = !isHidden
        self.datePicker.isHidden = !isHidden
    }

    @IBAction func tapStart(_ sender: UIButton) {
        self.duration = Int(self.datePicker.countDownDuration) // 2분 -> 120초와 같이 저장해줌.
//        debugPrint(self.duration)
        
        switch self.timerStatus {
        case .end:
            self.currentSeconds = self.duration
            self.timerStatus = .start
            self.setTimerInfoViewVisible(isHidden: false)
            self.startTimer()
        case .start:
            self.timerStatus = .pause
            self.btnStart.isSelected = false
            self.timer?.suspend()   // 타이머 일시정지
        case .pause:
            self.timerStatus = .start
            self.btnStart.isSelected = true
            self.timer?.resume()
        }
    }
}

Gitpporter Privacy

Published on January 02, 2023

(PillSoGood) 지원

Published on November 20, 2022