목표 : Timer 사용, Optional의 이해, ProgressBar/View 사용
https://github.com/appbrewery/EggTimer-iOS13
Egg Timer Project
main storyboard
에서 View Controller Scene
을 보면 우리는 아래에서 위로 본다고 생각하면 된다. 이미지를 보면 Image View
가 Button
보다 아래 있으므로 Button
은 Image View
에 의해 숨겨지게 된다.
Minimum Font Size
화면 사이즈가 각 아이폰 별로 다를 때 width
/height
의 크기가 줄어듬에 따라 label
의 텍스트가 잘리는 경우
- 두 가지 방법
1. Inspector
의 Lines
를 0으로 설정
2. Autoshrink
를 Minimum Font Size
로 설정 후, 최솟값 설정(Font Size)
IBAction 연결
main storyboard
의 이미지를 View Controller
로 연결해주겠음!
Button
을 Action type
으로 설정하고 Type
을 Any
가 아닌 UIButton
으로 수정해준다. 그리고 모든 이미지를 @IBAction
에 모두 연결해준다.
class ViewController: UIViewController {
@IBAction func pressedTimer(_ sender: UIButton) {
print(sender.currentTitle!)
}
}
버튼을 눌렀을 때 정확한 title 이름이 나오게 하려면 sender.currentTitle
을 사용하면 아래와 같이 디버그 창에 정확한 이름이 나오게 된다.
If, else if, else / Switch / Dictionary / Optional
If, else if, else
if문을 사용해서 각각의 이미지를 클릭했을 때 time이 디버그에 표시되려면 아래와 같이 코드를 구현하면 된다.
class ViewController: UIViewController {
let softTime = 5
let mediumTime = 7
let HardTime = 12
@IBAction func pressedTimer(_ sender: UIButton) {
let hardness = sender.currentTitle!
if hardness == "Soft" {
print(softTime)
} else if hardness == "Medium" {
print(mediumTime)
} else {
print(HardTime)
}
}
}
Switch
위 if
문을 switch
문으로 바꾸면 아래와 같다.
switch hardness {
case "Soft":
print(softTime)
case "Medium":
print(mediumTime)
case "Hard":
print(HardTime)
default:
print("아무것도 선택되지 않았습니다.")
}
Dictionary
이번에 할 Dictionary Challenge는 sotockTickers에 아래와 같은 Dictionary
를 추가해야 한다
"Work": "Slack Technologies Inc"
"Boom": "DMC Global Inc"
func exercise() {
//Don't change this
var stockTickers: [String: String] = [
"APPL" : "Apple Inc",
"HOG": "Harley-Davidson Inc",
"BOOM": "Dynamic Materials",
"HEINY": "Heineken",
"BEN": "Franklin Resources Inc"
]
//Write your code here.
//Don't modify this
print(stockTickers["WORK"]!)
print(stockTickers["BOOM"]!)
}
완성
//Write your code here.
stockTickers["WORK"] = "Slack Technologies Inc"
stockTickers["BOOM"] = "DMC Global Inc"
Timer
swift에서 timer의 사용 해려고 한다. 구글링을 통해 아래와 같은 솔루션을 찾았다. ( countdown timer swift stack overflow )
첫 번째 솔루션
var secondsRemaining = 30
override func viewDidLoad() {
super.viewDidLoad()
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
}
@objc func updateCounter() {
//example functionality
if secondsRemaining > 0 {
print("\(counter)초")
secondsRemaining -= 1
}
}
1. secondsRemaining
변수 생성
2. Timer
의 timeInterval
은 1초마다 업데이트를 원하기 때문에 1.0
으로 설정
3. selector
는 Objective-C
에서 사용하던 것을 가져왔기 때문에 함수에 @objc
를 사용한다.
4. updateCounter()
함수는 secondsRemaining
가 0보다 크면 secondsRemaining
를 -1 하면서 print
한다.
두 번째 솔루션
var secondsRemaining = 30
@IBAction func startTimer(_ sender: UIButton) {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
if self.secondsRemaining > 0 {
print ("\(self.secondsRemaining)초")
self.secondsRemaining -= 1
} else {
Timer.invalidate()
}
}
}
1. secondsRemaining
변수 생성
2. Timer
의 timeInterval
은 1초마다 업데이트를 원하기 때문에 1.0
으로 설정
3. if
문을 Timer
안에 사용하여 secondsRemaining
가 0보다 크면 secondsRemaining
를 -1 하면서 print
한다. 설정한 time이 끝나면 else
문으로 가서 Timer
가 invalidate()
되게 한다. ( invalidate = 타이머를 멈춤/취소시킴 )
Timer 사용
class ViewController: UIViewController {
let eggTimes = ["Soft": 5, "Medium": 7, "HardTime": 12]
var secondsRemaining = 0
@IBAction func pressedTimer(_ sender: UIButton) {
let hardness = sender.currentTitle!
secondsRemaining = eggTimes[hardness]!
print("시작")
// 타이머 구현부
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
if self.secondsRemaining > 0 {
print ("\(self.secondsRemaining)초")
self.secondsRemaining -= 1
} else {
Timer.invalidate()
print("완성")
}
}
}
}
문제점
문제점 : 타이머가 끝나기 전에 다른 버튼을 연속해서 클릭할 때 타이머가 취소되고 재 실행되는 것이 아닌 중복으로 실행이 된다.
해결방법 : 새로운 timer 가변 코드를 생성하여 타이머와 동일하게 설정해주고 클릭 시 취소되는 코드를 넣어줌
invalidate?
타이머가 다시 실행되는 것을 중지하고 런 루프에서 제거를 요청한다. 이 메서드는 개체 에서 타이머를 제거하는 유일한 방법 이다.
class ViewController: UIViewController {
let eggTimes = ["Soft": 5, "Medium": 7, "HardTime": 12]
var secondsRemaining = 0
var timer = Timer()
@IBAction func pressedTimer(_ sender: UIButton) {
// 버튼을 클릭했을때 취소시킴
timer.invalidate()
let hardness = sender.currentTitle!
secondsRemaining = eggTimes[hardness]!
print("시작")
// 타이머 구현부 ( tiemr = )
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
if self.secondsRemaining > 0 {
print ("\(self.secondsRemaining)초")
self.secondsRemaining -= 1
} else {
Timer.invalidate()
print("완성")
}
}
}
}
타이머 종료 후 label text 변경
타이머가 종료되면 Label Text
가 변경되도록 해줄 수 도 있다.
// 타이머 구현부 ( tiemr = )
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
if self.secondsRemaining > 0 {
print ("\(self.secondsRemaining)초")
self.secondsRemaining -= 1
} else {
Timer.invalidate()
self.timerLabel.text = "계란이 다 삶아졌습니다!"
}
ProgressView
main storyboard
에 progress View
를 추가하고 containers
와 height
, tint color
를 추가해준다.
이것을 ViewController
에 연결해서 progressView
를 꽉 채워보겠음!
@IBOutlet
으로 연결 > progressBar.progress = 1.0
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var timerLabel: UILabel!
@IBAction func pressedTimer(_ sender: UIButton) {
progressBar.progress = 1.0
...
}
progressView
를 Timer
와 연결하려면 백분율을 사용해야 함.
import UIKit
class ViewController: UIViewController {
let eggTimes = ["Soft": 5, "Medium": 7, "HardTime": 12]
var secondsPassed = 0
var totalTime = 0
var timer = Timer()
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var timerLabel: UILabel!
@IBAction func pressedTimer(_ sender: UIButton) {
// 버튼을 클릭했을때 취소시킴
timer.invalidate()
let hardness = sender.currentTitle!
totalTime = eggTimes[hardness]!
// 재실행 됐을때 초기화
progressBar.progress = 0.0
secondsPassed = 0
timerLabel.text = hardness
// 타이머 구현부 ( tiemr = )
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
// secondsPassed = 0 이고 totalTime이 hardness(3) 이므로
if self.secondsPassed < self.totalTime {
// secondsPassed + 1 하고 이것이 hardness까지 온다면
self.secondsPassed += 1
// secondsPassed / totalTime
self.progressBar.progress = Float(self.secondsPassed)/Float(self.totalTime)
} else {
Timer.invalidate()
self.timerLabel.text = "계란이 다 삶아졌습니다!"
}
}
}
}
진행시간 표시
1. ProgressView
아래 Label
추가
2. Containers
설정
3. viewController
에 @IBOutlet
연결
4. 타이머 구현부에 self.progressTime.text
로 원하는 텍스트 추가 ( text는 String이지만 secondsPassed는 Int 타입이므로 타입 변환을 해줘야 한다.)
5. 타이머가 끝나면 표시될 text 추가
class ViewController: UIViewController {
...
@IBOutlet weak var progressTime: UILabel!
...
@IBAction func pressedTimer(_ sender: UIButton) {
...
// 타이머 구현부 ( tiemr = )
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
if self.secondsPassed < self.totalTime {
// 지속시간 텍스트 표시
self.progressTime.text = "진행 시간 : \(Int(self.secondsPassed))초"
...
} else {
...
self.progressTime.text = "Time over!"
}
}
}
}
Play Sound
import AVFoundation
player: AVAudioPlayer!
변수 생성playSound
함수 구현- 타이머 구현부
else
문에playSound
함수 호출
import UIKit
import AVFoundation
class ViewController: UIViewController {
...
var player: AVAudioPlayer!
...
@IBAction func pressedTimer(_ sender: UIButton) {
...
// 타이머 구현부 ( tiemr = )
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
if self.secondsPassed < self.totalTime {
...
} else {
...
// 타이머 종료시 sound play
self.playSound(title: "alarm_sound")
}
}
}
func playSound(title: String?) {
let url = Bundle.main.url(forResource: title, withExtension: "mp3")
player = try!AVAudioPlayer(contentsOf: url!)
player.play()
}
}
전체 코드
import UIKit
import AVFoundation
class ViewController: UIViewController {
let eggTimes = ["Soft": 5, "Medium": 7, "HardTime": 12]
var secondsPassed = 0
var totalTime = 0
var timer = Timer()
var player: AVAudioPlayer!
@IBOutlet weak var progressTime: UILabel!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var timerLabel: UILabel!
@IBAction func pressedTimer(_ sender: UIButton) {
// 버튼을 클릭했을때 취소시킴
timer.invalidate()
let hardness = sender.currentTitle!
totalTime = eggTimes[hardness]!
// 재 실행시 초기화 설정
progressBar.progress = 0.0
secondsPassed = 0
timerLabel.text = hardness
// 타이머 구현부 ( tiemr = )
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
// secondsPassed = 0 이고 totalTime이 hardness(3) 이므로
if self.secondsPassed < self.totalTime {
// secondsPassed + 1 하고 이것이 hardness까지 온다면
self.secondsPassed += 1
// 지속시간 텍스트 표시
self.progressTime.text = "진행 시간 : \(Int(self.secondsPassed))초"
// secondsPassed / totalTime
self.progressBar.progress = Float(self.secondsPassed)/Float(self.totalTime)
} else {
Timer.invalidate()
self.timerLabel.text = "계란이 다 삶아졌습니다!"
self.progressTime.text = "Time over!"
// 타이머 종료시 sound play
self.playSound(title: "alarm_sound")
}
}
}
func playSound(title: String?) {
let url = Bundle.main.url(forResource: title, withExtension: "mp3")
player = try!AVAudioPlayer(contentsOf: url!)
player.play()
}
}
느낀점
🦊 timer를 사용하는법과 백분률을 사용하는법을 조금 더 이해할 필요가 있겠다..
🦊 progressView 사용법은 생각 보다 쉽진 않네..
🦊 타이머를 정지하고 취소할때는 invalidate() 사용!
'SWIFT > Udemy iOS' 카테고리의 다른 글
[Udemy] 섹션 10: iOS App Design Pattern Challenge (0) | 2021.08.05 |
---|---|
[Udemy] 섹션9: MVC 패턴, Struct, mutating ( 퀴즈 앱 ) (0) | 2021.08.02 |
[Udemy] 섹션7: Play Sound 및 Bundle - 실로폰 만들기 (0) | 2021.07.30 |
[Udemy] 섹션6: Auto Layout and Responsive UIs (오토레이아웃, 반응형 UI) (0) | 2021.07.30 |
[Udemy] 섹션 4: Swift 프로그래밍 - IBOutlet, IBAction (2) | 2021.07.29 |