일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 네이버 부스트캠프
- 운영체제
- 데이터베이스 공부
- SWIFT
- Apple Developer Academy @ POSTECH
- 애플 디벨로퍼 아카데미 후기
- OS
- ObservedObject
- swift문법
- 치지직
- Swift 디자인패턴
- global soop
- 데이터베이스
- StateObject
- Swift 기능
- 제앱소
- sqoop
- iOS 개발 오류
- Swift 문법
- 애플 아카데미 후기
- 네이버 치지직
- ObservableObject
- 애플 디벨로퍼 아카데미
- 앱 비교 프로젝트
- 숭실대
- react
- apple developer academy 후기
- 애플 디벨로퍼 아카데미 21주차 회고
- 소프트웨어분석및설계
- useReducer
- Today
- Total
사과하는 제라스
[Swift 기능] Timer 설정 방법 2가지 - 클로져 함수 / selector 본문
목차
Timer를 써보면 schedule을 할당해주는 방법이 여러가지가 존재한다. 그 중 2가지를 소개하고자 한다.
구현을 하다보면 정해진 간격의 시간마다, 정해진 시간동안 어떤 일을 수행하는 동작을 구현해야 할 때가 생긴다.
이러한 것을 돕는 것이 바로 timer다.
이전에 부스트캠프를 하면서도 사용했던 것인데 이번 공부를 하면서 가볍게라도 정리를 해보자!
1. 클로져 함수
@IBAction func startButtonDidTapped(_ sender: UIButton) {
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [self] _ in
if number > 0 {
number -= 1
self.slider.setValue(Float(number)/Float(60), animated: true)
mainLabel.text = "\(number) 초"
} else {
number = 0
mainLabel.text = "초를 선택하세요"
timer?.invalidate()
let systemSoundID: SystemSoundID = 1016
AudioServicesPlaySystemSound(systemSoundID)
}
}
}
이 코드처럼 클로져 함수를 줄 수 있다. 이때 유의해야 할 점이 바로 순환 참조이다.
마치 이런 형태가 될 수 있는데 timer라는 변수를 만들고 그 변수는 Timer 라이브러리로부터 만들고 Timer에서는 클로져 함수를 참조한다.
근데, 이때 클로져 함수를 위 코드처럼 [self]를 해두면 timer를 다시 강한 참조를 한다. 이렇게 되면 순환참조가 발생하고 코드가 계속 사라지지 않는 이슈가 발생할 수 있다.
이를 방지하기 위해서는 다음과 같이 timer를 weak로 약한 참조로 생성을 해야한다.
weak var timer: Timer?
이렇게 하면 timer 변수가 Timer를 약한 참조를 하기 때문에 순환 참조를 방지할 수 있다. 다음 그림처럼 볼 수 있다.
만약 weak으로 안했다면 클로져 함수 내 [self]를 [weak self]로 주는 방법도 있다.
2. selector
이 방법을 쓰면 순환참조에 대한 고민을 좀 덜 수 있다. 다음과 같은 코드를 작성하는 것이다.
@IBAction func startButtonDidTapped(_ sender: UIButton) {
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(doSomethingAfter1Sec), userInfo: nil, repeats: true)
}
@objc func doSomethingAfter1Sec() {
if number > 0 {
number -= 1
self.slider.setValue(Float(number)/Float(60), animated: true)
mainLabel.text = "\(number) 초"
} else {
number = 0
mainLabel.text = "초를 선택하세요"
timer?.invalidate()
let systemSoundID: SystemSoundID = 1016
AudioServicesPlaySystemSound(systemSoundID)
}
}
이렇게 쓰는 방법인데 selector로 objc 함수를 주고(selector에는 항상 objc 함수를 할당해야 한다고 함, #selector를 쓰고 그 안에 실행할 함수이름을 적어넣으면 됨.) 해당 함수를 주어진 interval마다 반복하는 방식이다.
이와 같은 방식으로 짜면 objc함수인 doSomethingAfterSec에서 timer라는 멤버 변수를 통해 접근을 할 수 있기에 따로 timer를 매개변수로 넘겨주지 않아도 되지만 만약 timer를 매개변수로 넘겨준다면 서로 순환 참조를 할 수 있기에 문제가 생길 수도 있다.
다음은 순환 참조가 생길 가능성이 있는 방식의 구현이다.
let timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(doSomethingAfter1Sec(_:)), userInfo: nil, repeats: true)
@objc func doSomethingAfter1Sec(_ timer: Timer) {
if number > 0 {
number -= 1
self.slider.setValue(Float(number)/Float(60), animated: true)
mainLabel.text = "\(number) 초"
} else {
number = 0
mainLabel.text = "초를 선택하세요"
timer?.invalidate()
let systemSoundID: SystemSoundID = 1016
AudioServicesPlaySystemSound(systemSoundID)
}
}
이렇게 하면 userInfo를 통해 timer의 요소들에 접근을 해서 사용할 수 있다는 장점이 있기는 하다. 대신 순환 참조를 방지하도록 타이머 무효화를 잘해주면 된다.
일단 클로져 함수를 순환 참조 고민까지 해가면서 하기에는 부담이 된다면 selector 함수를 쓰는 것도 좋은 것 같다. 이 부분은 어떤 것을 쓰는게 코드적으로, 성능적으로 좋을지는 차차 알아가보도록 하자.
'제라스의 iOS 공부 > Swift 기능' 카테고리의 다른 글
[Swift 기능] Alert 기능을 구현해보자 (0) | 2023.09.18 |
---|---|
[Swift 기능] Auto-Layout을 스토리보드 사용하지 않고 코드로 구현 (0) | 2023.09.18 |
[Swift 기능] 뷰의 모서리를 설정해보자!(with cornerRadius, masksToBounds) (0) | 2023.09.17 |
[Swift 기능] 입력창 외부를 클릭 시 키보드가 내려가는 기능 구현 (0) | 2023.09.17 |
[Swift 기능] UITextFieldDelegate의 함수들을 알아보자 (0) | 2023.09.17 |