본 포스팅은 다음 버전을 기준으로 작성되었습니다.
- Swift 5.3
- iOS 14.1
Intro
오늘은 DatePicker
에서 제공하는 Mode 중 하나인 .countDownTimer
를 사용해 실제로 구동 가능한 타이머를 만들어보겠습니다.
Prerequisite
타이머 구현 및 실습을 위해 DatePicker
를 배치하고, 상단에는 타이머의 남은 시간을 표시할 UILabel
을,
하단에는 사용자가 설정한 시간을 기준으로 타이머 구동을 시작할 UIButton
을 배치했습니다.
import UIKit
class CountDownViewController: UIViewController {
let label = UILabel()
let picker = UIDatePicker()
let button = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
// MARK: - UI
private func configureUI() {
setAttributes()
setContraints()
}
private func setAttributes() {
label.text = "0"
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 30)
picker.datePickerMode = .countDownTimer
button.setTitle("Start", for: .normal)
button.addTarget(self, action: #selector(handleButton(_:)), for: .touchUpInside)
}
private func setContraints() {
[label, picker, button].forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.bottomAnchor.constraint(equalTo: picker.topAnchor, constant: -100),
picker.centerYAnchor.constraint(equalTo: view.centerYAnchor),
picker.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
picker.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.topAnchor.constraint(equalTo: picker.bottomAnchor, constant: 150)
])
}
// MARK: - Selectors
@objc
private func handleButton(_ sender: UIButton) {
print(picker.countDownDuration)
print(#function)
}
}
이제 Simulator 를 실행하고 버튼을 눌러보면 Console 에 사용자가 선택한 시간이 출력되는 것을 확인할 수 있어요.
Analyzing Methods
이제 DatePicker
의 설정을 실습에 맞게 바꿔주고, Timer 기능을 수행할 코드를 작성해보도록 할게요.
CountDown Duration 조절하기
이 옵션은 datePicker
가 .countdownTimer
로 설정되어 있을 때만 사용할 수 있고, 최초에 설정되어 있는 값을 조절할 수 있습니다.
초 단위 설정이 가능하기는 하지만 화면에 표시될 때는 분 단위로 표시되기 때문에 60의 배수로 설정해주세요.
picker.countDownDuration = 600
앱을 실행하자마자 기본 시간이 10분으로 설정되어 있습니다.
Minute 선택 간격 조절하기
사용자가 datePicker
를 스크롤하며 선택할 수 있는 옵션을 제어합니다.
picker.minuteInterval = 5
이 옵션을 적용하고 실행해보면 타이머가 5분 간격으로 선택되는 것을 확인할 수 있을거에요.
Timer 기능 구현하기
DatePicker
자체는 타이머 기능을 수행할 수 있는 어떤 옵션도 없습니다. 단지 인터페이스의 역할만 수행할 뿐이에요.
그래서 우리가 Timer
인스턴스를 직접 생성하고 남은 시간을 관리해야 타이머 기능을 구현할 수 있습니다.
버튼이 눌렸을 때 사용자가 설정한 시간을 입력받아 해당 값을 기준으로 타이머 기능을 만들어주도록 하겠습니다.
먼저 타이머가 0초가 되었을 때 알람을 실행하도록 만들어볼게요.
AudioServicesPlaySystemSound
를 사용해 기본 사운드를 재생하고 이 method 를 사용하기 위해 AVFoundation
을 import 합니다.
import AVFoundation
사용자가 설정한 값을 입력받을 변수가 하나 필요합니다. ViewController 상단에 변수를 하나 생성하도록 할게요.
var duration: Int = 0
이제 버튼과 연결해 놓은 함수에 타이머와 관련된 코드를 작성하겠습니다.
@objc
private func handleButton(_ sender: UIButton) {
duration = Int(picker.countDownDuration)
label.text = "\(duration)"
Timer.scheduledTimer( withTimeInterval: 1, repeats: true) {
(timer) in
self.duration -= 1
self.label.text = "\(self.duration)"
if self.duration == 0 {
timer.invalidate()
AudioServicesPlaySystemSound(1315)
}
}
}
Timer
는 반드시 직접 종료해주어야 하는 것을 잊지마세요. 해제는 .invalidate
method 를 사용해 구현할 수 있습니다.
Wrap Up
이렇게 DatePicker
를 .countDownTimer
모드로 사용할 수 있는 방법과, Timer
인스턴스와 연계해 실제로 타이머 기능을 구현할 수 있는 방법에 대해 공부해보았습니다.
이제 DatePicker
의 주요 기능들에 대해 충분히 공부했으니 필요한 프로젝트에 적용해 보세요!
Entire Code
import UIKit
import AVFoundation
class CountDownViewController: UIViewController {
let label = UILabel()
let picker = UIDatePicker()
let button = UIButton(type: .system)
var duration: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
// MARK: - UI
private func configureUI() {
setAttributes()
setContraints()
}
private func setAttributes() {
label.text = "0"
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 30)
picker.datePickerMode = .countDownTimer
picker.countDownDuration = 60
picker.minuteInterval = 1
button.setTitle("Start", for: .normal)
button.addTarget(self, action: #selector(handleButton(_:)), for: .touchUpInside)
}
private func setContraints() {
[label, picker, button].forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.bottomAnchor.constraint(equalTo: picker.topAnchor, constant: -100),
picker.centerYAnchor.constraint(equalTo: view.centerYAnchor),
picker.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
picker.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.topAnchor.constraint(equalTo: picker.bottomAnchor, constant: 150)
])
}
// MARK: - Selectors
@objc
private func handleButton(_ sender: UIButton) {
duration = Int(picker.countDownDuration)
label.text = "\(duration)"
Timer.scheduledTimer( withTimeInterval: 1, repeats: true) {
(timer) in
self.duration -= 1
self.label.text = "\(self.duration)"
if self.duration == 0 {
timer.invalidate()
AudioServicesPlaySystemSound(1315)
}
}
}
}