我刚刚开始使用 Swift 并将 MVVM 与依赖注入(inject)结合使用。
在我的 ViewModel 中,我有处理刷新数据的计时器。为了清楚起见,我稍微简化了代码。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let viewModel = ViewModel()
}
}
class ViewModel: NSObject {
private var timer: Timer?
override init() {
super.init()
setUpTimer()
}
func setUpTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true){_ in
self.refreshData()
}
}
func refreshData() {
//refresh data
print("refresh data")
}
}
我想使用依赖注入(inject)将定时器传递给 ViewModel,这样我就可以在进行单元测试时控制定时器并使其立即调用。
因此传递 Timer 非常简单。如何将计时器传递给能够调用属于 ViewModel 的 refreshData() 的 ViewModel。 Swift 中有允许这样做的技巧吗?
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true){_ in
// call refreshData() from the class ViewModel
}
var viewModel = ViewModel(myTimer:timer)
}
}
class ViewModel: NSObject {
private var timer: Timer?
init(myTimer:Timer) {
super.init()
//setUpTimer()
timer = myTimer
}
func refreshData() {
//refresh data
print("refresh data")
}
}
我认为使用带有选择器而不是 block 的 scheduelTimer 可能是可能的,但这需要在 func refreshData() 之前使用 @objc,这看起来很笨重,因为我在 Swift 中使用 Objective C 功能。
有什么好的方法可以做到这一点吗?
非常感谢, 代码
最佳答案
从概念上讲,您想要分离实现。因此,不必将 Timer
传递给 View 模型,而是传递一些其他“控制”对象,它保证执行操作(延迟后回调)
如果那不叫 protocol
,我不知道是什么...
typealias Ticker = () -> Void
protocol Refresher {
var isRunning: Bool { get }
func register(_ ticker: @escaping Ticker)
func start();
func stop();
}
所以,非常基本的概念。它可以启动、停止,并且观察者可以将自己注册到它并在“滴答声”发生时得到通知。观察者不关心它“如何”工作,只要它保证执行指定的操作即可。
基于 Timer
的实现可能看起来像...
class TimerRefresher: Refresher {
private var timer: Timer? = nil
private var ticker: Ticker? = nil
var isRunning: Bool = false
func register(_ ticker: @escaping Ticker) {
self.ticker = ticker
guard timer == nil else {
return
}
}
func start() {
guard ticker != nil else {
return
}
stop()
isRunning = true
timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true, block: { (timer) in
self.tick()
})
}
func stop() {
guard let timer = timer else {
return
}
isRunning = false
timer.invalidate()
self.timer = nil
}
private func tick() {
guard let ticker = ticker else {
stop()
return
}
ticker()
}
}
这为您提供了模拟依赖项注入(inject)的入口点,通过将 Refresher
的实现替换为您可以手动控制的实现(或使用不同的“延迟”操作,具体取决于您的需要)
这只是一个概念性示例,您的实现/需求可能会有所不同并导致您的设计略有不同,但想法保持不变,以某种方式解耦物理实现。
替代方案需要您重新考虑您的设计,而不是 View 模型执行它自己的刷新, View / Controller 将接管该责任。由于这是一个重要的设计决定,您实际上只是可以做出该决定的人,但这是另一个想法
关于ios - 定时器和依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51956833/