할말은 주석에 다 써놨다.
// import Combine 까먹지 말것
import UIKit
import Combine
// UIKit에서는 ObservableObject 프로토콜을 채택 안해도 동작함.
// SwiftUI에서는 @StateObject 로 ViewModel 을 선언해야 하기 때문에 꼭 필요함.
// 예제에서는 그냥 멋있어 보이려고 채택함
class TimerClass: ObservableObject {
// 프로퍼티에 @Published 프로퍼티 래퍼를 달아주면 값을 발행(publish) 할 수 있게 됨
@Published var count: Int = 0
var timer: Timer = Timer()
init() {
initTimer()
}
func initTimer() {
//1초에 한번 publish 하는 값을 +1씩 갱신
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in
guard let self = self else { return }
self.count += 1
})
}
func stopTimer() {
self.timer.invalidate()
}
}
class CombineTimerExampleViewController: UIViewController {
let timerViewModel: TimerClass = TimerClass()
let timerCount: UILabel = UILabel()
let stopButton: UIButton = UIButton()
//구독자의 타입인 Cancellable이 담길 곳
var cancellable: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
//뷰 셋업
setupView()
//뷰 바인딩
bind()
}
private func bind() -> () {
// 뷰에 갱신될 값은 구독 함수인 sink() 를 통해서 구독됨.
// sink()가 방출하는 값은 AnyCancellable 타입이고, 이걸 위해 만들어둔 self.cancellable에 담고
// sink()클로저에 어느 뷰와 묶어줄지만 선언해주면 알아서 값이 바뀔 때마다 뷰가 갱신됨.
// 주의해야 할 점은 뷰 갱신을 위해 @Published 프로퍼티를 받아올 때에는 $수정자를 붙여야 함 (.count 가 아니고 .$count)
self.cancellable = timerViewModel.$count.sink { [weak self] count in
guard let self = self else { return }
self.timerCount.text = "\(count)"
}
}
private func setupView() -> () {
timerCount.textAlignment = .center
timerCount.font = UIFont.systemFont(ofSize: 30)
timerCount.translatesAutoresizingMaskIntoConstraints = false
stopButton.configuration = .borderedProminent()
stopButton.configuration?.title = "Stop Timer"
stopButton.addTarget(self, action: #selector(stopTimer), for: .touchUpInside)
stopButton.translatesAutoresizingMaskIntoConstraints = false
self.view.backgroundColor = UIColor.systemBackground
self.view.addSubview(timerCount)
self.view.addSubview(stopButton)
NSLayoutConstraint.activate([
timerCount.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
timerCount.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
timerCount.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: -40),
timerCount.heightAnchor.constraint(equalToConstant: 40),
stopButton.topAnchor.constraint(equalTo: timerCount.bottomAnchor, constant: 20),
stopButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
])
}
@objc func stopTimer() {
//타이머 멈추기
timerViewModel.stopTimer()
}
}
WRITTEN BY
- artfrige
베이스 연주는 건강에 좋습니다
,