์๋ ํ์ธ์~!
์ค๋์ ํผ์ค๋ ๋ชจ๋น๋ฆฌํฐ์ฑ์์ ํ์ด๋จธ๋ฅผ ์ด์ฉํด์ ์ด์ฉ์๊ฐ์ ๊ตฌํํ ๋ถ๋ถ์ ๊ธฐ๋กํด๋ณด๋ ค๊ณ ํฉ๋๋ค!โจ
ํ๋ก์ ํธ ๊ธฐ๊ฐ ์ค ๊ธฐ๊ฐ์ผ์ ์งํค๊ธฐ ์ํด ์ ์ ์์ด ๋ฌ๋ฆฌ๋ค ๋ณด๋ ๊ธฐ๋ก์ ๋ง์ด ๋ชปํ ์ ์ด ์์ฌ์์
์ด๋ฒ์ฃผ๋ ํ๋ก์ ํธ ๊ธฐ๊ฐ ์ค์ ๊ณต๋ถํ๋ ๋ด์ฉ์ ์์ฃผ๋ก ํฌ์คํ ์ ์งํํ๋ ค๊ณ ํฉ๋๋ค~!
๋๋ฌด๋๋ฌด ๋ฐ๋น ๋ ๊ธฐ๋ก์ ๊ผญ ์ฑ๊ธฐ๊ธฐโญ๏ธ
์ด๊ธฐ๊ตฌํ๋ฐฉ๋ฒ
ํฅ๋ณด๋์ ๋์ฌํ๊ธฐ๋ฅผ ๋๋ ์ ๋, ํฅ๋ณด๋์ ๋์ฌ์๊ฐ์ ๋ณด์ฌ์ฃผ๋๋ก UI๋ฅผ ๊ตฌ์ฑํ์์ด์!
์ฒ์์๋ ๋์ฌํ ํฅ๋ณด๋๋ฅผ ์ ์ฅํ๋ ๋ฐ์ดํฐ์ "๋์ฌํ๊ธฐ" ๋ฒํผ์ ๋๋ ์ ๋์ ์๊ฐ์ ์ ์ฅํด ๋ ๋ค ๊ทธ ์๊ฐ๊ณผ ํ์ฌ์ ์๊ฐ์ ์ฐจ๋ฅผ ๊ตฌํ์ฌ ์ด์ฉ์๊ฐ์ด ์ ์ฅํ๋๋ก ๊ตฌํํ์์ด์.
func calculateKickboardTotalTime() -> Int {
guard let start = getUserDefaultsKickboardStartTime().toDate() else {
return 0
}
return Int(Date().timeIntervalSince(start) / 60)
}
ํ์ง๋ง, ๋ฌธ์ ๋ ์ค์๊ฐ์ผ๋ก ์ ์ฉ์ด ๋์ง ์๋๋ค๋ ๋ฌธ์ ์์ต๋๋ค. View๋ฅผ ๋ค์ ๊ทธ๋ฆด ๋๋ ์๊ฐ์ด ์ ๋ฐ์ดํธ๋์ด์ ์๊ฐ์ด ๋ํ๋์ง๋ง, 1๋ถ์ด ์ง๋ ๋๋ง๋ค ์ค์๊ฐ์ผ๋ก ๋ณํ๋ ์๊ฐ์ ์ ์ฉํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ์ด์!
๊ทธ๋์ Timer๋ฅผ ์ ์ฉํ์์ต๋๋ค.
Timer
Timer๋ Foundation ํ๋ ์์ํฌ์ ์ ์๋์ด ์๋ ๊ฐ์ฒด๋ก ํน์ ์๊ฐ์ ๊ฐ๊ฒฉ์ผ๋ก ์ฝ๋ ๋ธ๋ก์ ๋ฐ๋ณต์ ์ผ๋ก ์คํํ๋๋ก ์์ฝํ๋๋ฐ ์ฌ์ฉ์ด ๋ฉ๋๋ค. RunLoop์์ ์๋์ ํ๊ณ , ํน์ ์๊ฐ์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ์ง์ ๋ ๊ฐ๊ฒฉ์ผ๋ก ๋ฐ๋ณต ์์ ์ ์ํํ ๋ ์ฃผ๋ก ์ฌ์ฉํฉ๋๋ค.
Timer ์์ฑ๋ฐฉ๋ฒ
scheduledTimer ํจ์๋ฅผ ํตํด Timer ๊ฐ ์๋์ผ๋ก ์์ฑ๋์ด ํ์ฌ ์ฑ์ RunLoop์ ์ถ๊ฐํ๊ณ ์คํํ ์ ์์ต๋๋ค.
// ํด๋ก์ ๋ฅผ ์ฌ์ฉํด ํ์ด๋จธ ํธ๋ฆฌ๊ฑฐ๊ฐ ์คํ๋ ๋, ์ฝ๋ ๋ธ๋ก์ ์ง์ ์ง์ ํ ์ ์์
func scheduledTimer(withTimeInterval: TimeInterval,
repeats: Bool,
block: (Timer) -> Void)
// objc selector๋ฅผ ์ด์ฉํด ํ์ด๋จธ ํธ๋ฆฌ๊ฑฐ๊ฐ ์คํ๋ ๋, ํธ์ถํ ๋ฉ์๋๋ฅผ ์ง์
// ๋ํ userInfo๋ฅผ ํตํด ํ์ด๋จธ ์คํ ์ ํ์ํ ์ถ๊ฐ ๋ฐ์ดํฐ ์ ๋ฌ ๊ฐ๋ฅ
func scheduledTimer(timeInterval: TimeInterval,
target: Any,
selector: Selector,
userInfo: Any?,
repeats: Bool)
// NSInvocation ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํด ํ์ด๋จธ ์ด๋ฒคํธ์ ๋ํ ์๋ต์ผ๋ก ํธ์ถ๋ ๋ ๋ฉ์๋๋ฅผ ์ง์
func scheduledTimer(timeInterval: TimeInterval,
invocation: NSInvocation,
repeats: Bool)
์์ ์ธ ํจ์ ์ค ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ ํจ์๋ ์ฒซ๋ฒ์งธ ํจ์๋ผ๊ณ ํฉ๋๋ค! ์ธ ํจ์์ ๊ณตํต์ ์ธ ๋ถ๋ถ์ด timeInterval๊ณผ repeats์ธ๋ฐ์!
- timeInterval : ์ด ๋จ์๋ก ํ์ด๋จธ๊ฐ ์คํ๋๋ ์ฃผ๊ธฐ
- repeats : ๋ฐ๋ณต ์ฌ๋ถ
- true - ํ์ด๋จธ๊ฐ ๋ฐ๋ณต
- false - ํ์ด๋จธ ๋ฐ๋ณต๋์ง ์์.
์์ง ์ธ๋ฒ์งธ ํจ์์ NSInvocation์ ๋ํ ์ง์์ ์์ด์ ๋ค์์ ๊ณต๋ถํด ๋ณด๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค~!
์ ์ฒซ๋ฒ์งธ ํจ์๋ฅผ ์ด์ฉํ์ฌ ํด๋ก์ ํจ์๋ฅผ ํตํด ํ์ด๋จธ๊ฐ ๋ฐ๋ณต์ด ๋ ๋๋ง๋ค ์คํ๋ ํจ์๋ฅผ ์ ์ํ์์ต๋๋ค.
Timer ์ ์ฉ
์ฒซ ๋ฒ์งธ, ํ์ด๋จธ๋ฅผ ๊ด๋ฆฌํ ํด๋์ค ํ์ฑ
import Foundation
class TimerManager {
static let shared = TimerManager()
private init() {}
}
์ฐ์ Timer๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ TimerManager ํด๋์ค๋ฅผ ๋ฐ๋ก ๋ง๋ค์์ด์!
static์ผ๋ก ์ ์ธ๋ share๋ผ๋ ๋ณ์์ TimerManager์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค๊ณ , ์์ฑ์๋ฅผ private๋ก ์ ์ธํจ์ผ๋ก์จ ํด๋น ํด๋์ค์ ์ธ์คํด์ค๋ shared ๋จ ํ๋๋ง์ ์ ์ธ๋๋๋ก ์ค์ ํ์ต๋๋ค.
๋ ๋ฒ์งธ, ๋ณ์์์ฑ
var timer: Timer?
var elapsedTime: Int = 0
Timer์ ์ธ์คํด์ค๋ฅผ ๋ด์ timer๋ผ๋ ๋ณ์๋ฅผ ์์ฑํ๊ณ , ์คํ์๊ฐ์ ์ธก์ ํ๊ธฐ ์ํ elapsedTime์ด๋ผ๋ ๋ณ์๋ฅผ ์์ฑํ์์ต๋๋ค.
์ธ ๋ฒ์งธ, Timer ์ธ์คํด์ค ์์ฑ
func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
// ํ์ด๋จธ๊ฐ 1์ด ํ๋ฅผ ๋๋ง๋ค ์คํํ ํจ์
}
}
์์์ ์ค๋ช ํ๋ ์ธ๊ฐ์ง ํจ์ ์ค ์ฒซ ๋ฒ์งธ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ Timer๋ฅผ ์๋์ผ๋ก ์์ฑํ์ฌ RunLoop์ ์ถ๊ฐํ๋๋ก ๊ตฌํํ์์ต๋๋ค. 1์ด๋ง๋ค ๋ฐ๋ณต๋์ด์ ์๊ฐ์ ์ ๋ฐ์ดํธํ๋๋ก ๊ตฌํํ๊ธฐ ์ํด TimeInterval์ 1๋ก, repeats๋ฅผ true๋ก ๋ง๋ค์ด์ฃผ์์ด์~!
? ์ฌ๊ธฐ์ [weak self]๋ผ๋ ํค์๋๋ฅผ ์ฌ์ฉํ๋ ์ด์
Time ๊ฐ์ฒด๋ ํด๋ก์ ๋ฅผ ์คํํ๊ธฐ ์ํด ์ด ํด๋ก์ ๋ฅผ ๋ด๋ถ์ ์ผ๋ก ์ฐธ์กฐํ๊ณ ์๋๋ฐ ํด๋ก์ ๊ฐ self๋ฅผ strong์ผ๋ก ์ฐธ์กฐํ๊ฒ ๋๋ฉด, TimerManager์ ์ธ์คํด์ค์ Timer ์ฌ์ด์ ๊ฐํ ์ฐธ์กฐ ์ฌ์ดํด์ด ํ์ฑํ๊ฒ ๋์ด ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐ์์ํฌ ์ ์๊ธฐ ๋๋ฌธ์ด์์~!
๋ค ๋ฒ์งธ, Timer๋ฅผ ์ค์ง์ํฌ ํจ์ ์์ฑ
func stopTimer() {
timer?.invalidate()
timer = nil
elapsedTime = 0
print("Timer stopped")
}
Timer๋ ๋ฌดํ ๋ฃจํ๋ฅผ ๋๋ ๊ฐ์ฒด์ด๋ฏ๋ก Timer๋ฅผ ์ค์งํ๋ ๋ถ๋ถ์ด ์์ฃผ ์ค์ํฉ๋๋ค~! Timer๋ฅผ ๋ฉ์ถ์ง ์์ผ๋ฉด ๋ฌดํ ๋ฃจํ์ ๋น ์ ธ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ญ๋นํ ์๋ ์์ต๋๋ค. ํ๋์ฉ ์ฝ๋๋ฅผ ๋ฏ์ด์ ์ค๋ช ํ์๋ฉด,
- timer?.invalidate() : ํ์ด๋จธ๊ฐ ๋ฏธ๋์ ์คํ๋๋ ๊ฒ์ ์ค์ง์ํค๊ณ , ํ์ด๋จธ์ ์คํ ๋ฃจํ์์ ์ ๊ฑฐํ๋๋ก ํฉ๋๋ค.
- timer = nil : ํ์ด๋จธ๋ฅผ nil๋ก ์ค์ ํจ์ผ๋ก์จ TimerManager์ ์ธ์คํด์ค๊ฐ Timer์ ๋ํ ๊ฐํ ์ฐธ์กฐ๋ฅผ ํด์ ํ๊ฒ ํด ์ค๋๋ค.
- elapsedTime : ํ์ฌ ์คํ ์๊ฐ์ 0์ผ๋ก ์ด๊ธฐํํฉ๋๋ค.
์ ๋๋ค.
๋ค์ฏ ๋ฒ์งธ, ํ์ด๋จธ๊ฐ 1์ด ํ๋ฅผ ๋๋ง๋ค ์คํ์ํฌ ํจ์ ์์ฑ
private func timerDidFire() {
elapsedTime += 1
print("Timer updated: \(elapsedTime) seconds")
NotificationCenter.default.post(name: "timerUpdated", object: nil)
}
์ฐ์ ํ์ฌ ์คํ์๊ฐ์ 1์ด ์ฌ๋ฆฌ๊ณ ์!
NotificationCenter์ ์ฑ๊ธํค ์ธ์คํด์ค๋ฅผ ์ฐธ์กฐํด postํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์ด๋จธ๊ฐ 1์ด ํ๋ฅผ ๋๋ง๋ค ์๋ฆผ์ ์ ์กํฉ๋๋ค.
์ด ํจ์๋ฅผ ์์ startTimer์์ ์คํ์์ผ ์ค๋๋ค!
์ฌ๊ธฐ์ Notification์ ์ด๋ฆ์ ์ ํ๋๋ฐ "timerUpdated"๋ผ๋ ๋ณ์๊ฐ ๋ณ๊ฒฝ๋๊ธฐ๋ ํ๊ณ , ์คํ๊ฐ ๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ๋ฐ๋ก ๋ณ์๋ฅผ ๋ง๋ค์ด ์์ฑํด ์ฃผ์์ด์~!
extension Notification.Name {
static let timerUpdated = Notification.Name("timerUpdated")
}
์ฌ์ฏ ๋ฒ์งธ, ์๋ฉธ์ ์์ฑ
deinit {
stopTimer()
NotificationCenter.default.removeObserver(self)
}
์ธ์คํด์ค๊ฐ ํด์ ๋๊ธฐ ์ง์ ์ ํธ์ถ๋๋ ์๋ฉธ์๋ฅผ ๊ตฌํํด ์ค๋๋ค!
ํ์ด๋จธ ์ค์ง์ notificationCenter์์ ์ต์ ๋ฒ๋ฅผ ์ญ์ ํด ์ฃผ์ด์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ํด๊ฒฐํด ์ค๋๋ค.
์ ์ฒดํจ์
//
// TimerManager.swift
// OneBoardProject
//
// Created by ๋ฐฐ์งํด on 4/28/24.
//
import Foundation
class TimerManager {
static let shared = TimerManager()
private init() {}
var timer: Timer?
var elapsedTime: Int = 0
func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
self?.timerDidFire()
}
}
func stopTimer() {
timer?.invalidate()
timer = nil
elapsedTime = 0
print("Timer stopped")
}
private func timerDidFire() {
elapsedTime += 1
print("Timer updated: \(elapsedTime) seconds")
NotificationCenter.default.post(name: .timerUpdated, object: nil)
}
deinit {
stopTimer()
NotificationCenter.default.removeObserver(self)
}
}
extension Notification.Name {
static let timerUpdated = Notification.Name("timerUpdated")
}
์ด์ ํ์ด๋จธ ํด๋์ค๋ฅผ ์์ฑํด ์คฌ์ผ๋ ํด๋น ํจ์๋ฅผ ํธ์ถํ์ฌ ์ฌ์ฉํด์ผ๊ฒ ์ฃ ?!
์ผ๊ณฑ ๋ฒ์งธ, 1์ด๊ฐ ์ง๋ ๋๋ง๋ค label ์ ๋ฐ์ดํธํ๊ธฐ
// 1์ด ์ง๋ ๋๋ง๋ค ํ์ด๋จธ ์
๋ฐ์ดํธ
NotificationCenter.default.addObserver(self,
selector: #selector(handleTimerUpdate),
name: .timerUpdated,
object: nil)
NotificationCenter์ addObserver๋ฅผ ์ฌ์ฉํด .timerUpdated๋ผ๋ ์ด๋ฆ์ ์๋ฆผ์ ๋ฐ์ ๋๋ง๋ค ์คํํ ํจ์ handleTimerUpdate๋ฅผ ์คํํ๋๋ก ํฉ๋๋ค.
// 1์ด๋ง๋ค label ์
๋ฐ์ดํธ ์ก์
@objc func handleTimerUpdate() {
// UI ์
๋ฐ์ดํธ๋ ๋ฉ์ธ ์ค๋ ๋์์ ์คํ
DispatchQueue.main.async {
let time = TimerManager.shared.elapsedTime
self.rentalmodal.durationTimeNumberLabel.text = "\(time/60)๋ถ \(time%60)์ด"
self.rentalmodal.totalPriceLabel.text = UserViewController().setPriceLabel(price: 500 + ( time / 60 ) * 180 )
}
}
UI ์ ๋ฐ์ดํธ๋ ๋ฉ์ธ ์ค๋ ๋์์ ์คํํด์ผ ํ๊ธฐ ๋๋ฌธ์ DispatchQueue.main.async๋ฅผ ์ฌ์ฉํด ์ฃผ๊ณ , TimerManager์ ์ฑ๊ธํค ์ธ์คํด์ค๋ฅผ ์ฐธ์กฐํ์ฌ ํ์ฌ ์คํ ์๊ฐ์ธ elpasedTime์ ๊ฐ์ ์ด์ฉํด rentalmodal์ ๋ผ๋ฒจ์ ์ ๋ฐ์ดํธํด์ฃผ์์ต๋๋ค.
์ผ๊ณฑ ๋ฒ์งธ, startTimer()์ stopTimer() ์คํํ๊ธฐ
Timer๋ ๋์ฌํ๊ธฐ ๋ฒํผ์ด ๋๋ ธ์ ๋, ํ์ด๋จธ๊ฐ ์์ํ๊ณ , ๋ฐ๋ฉํ๊ธฐ ๋ฒํผ์ด ๋๋ ธ์ ๋, ํ์ด๋จธ๊ฐ ์ข ๋ฃ๋๋๋ก ํ์ฌ ํฅ๋ณด๋๋ฅผ ๋ ํธํ์ ๋๋ง์ ์๊ฐ์ ์ธก์ ํ๋๋ก ๊ตฌํํ์์ต๋๋ค.
// MARK: - ํฅ๋ณด๋ ๋์ฌ ๋ฒํผ
@IBAction func rentButtonTapped(_ sender: UIButton) {
// ...
// ์ฝ๋ ์๋ต
// ...
// ํ์ด๋จธ ์์
TimerManager.shared.startTimer()
}
// MARK: - ํฅ๋ณด๋ ๋ฐ๋ฉ ๋ฒํผ
@IBAction func returnBikeButtonTapped(_ sender: UIButton) {
if isSelectedAnnotation {
isSelectedAnnotation = false
// ...
// ์ฝ๋ ์๋ต
// ...
// ํ์ด๋จธ ์ข
๋ฃ
NotificationCenter.default.removeObserver(self)
TimerManager.shared.stopTimer()
}else {
returnAlertAction?()
print("์ด๋
ธํ
์ด์
์ด ์ ํ๋์ง ์์")
}
}
๊ตฌํํ๋ฉด