Swift中如何基于计算型布尔变量启停Timer?
Swift中基于计算型布尔变量启停Timer的解决方案
问题背景
需要在SwiftUI视图中,根据计算型布尔变量isActive(判断逻辑为fetcher.currentItemId == item.id)控制Timer的启停。当前代码能实现Timer的取消,但无法重新创建启动Timer。
原代码
struct TestView: View { @EnvironmentObject var fetcher: TestFetcher var item: Item var isActive: Bool { fetcher.currentItemId == item.id } @State private var counter = 0 @State private var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() var body: some View { HStack { Text("\(counter)") .onReceive(timer) { _ in if (isActive) { counter += 1 } else { timer.upstream.connect().cancel() } } } } }
尝试过的错误方式
方式1:将Timer设为计算属性
var timer: Any? { if (fetcher.currentItemId == item.id) { return Timer.publish(every: 1, on: .main, in: .common).autoconnect() } else { return timer.connect().cancel() } }
报错信息:
Instance method 'onReceive(_:perform:)' requires that 'Any?' conform to 'Publisher'
问题原因:计算属性返回Any?类型,不符合onReceive要求的Publisher类型,且cancel()无返回值,逻辑写法错误。
方式2:在计算属性isActive中修改Timer
var isActive: Bool { let _bool = fetcher.currentItemId == item.id if (_bool) { self.timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() } else { self.timer.connect().cancel() } return _bool }
无效原因:计算属性不能修改自身或其他存储属性,也没有didSet监听回调,无法触发Timer的创建逻辑。
正确实现方案
使用AnyCancellable管理Timer的订阅生命周期,配合.onChange监听isActive的变化来启停Timer:
import Combine import SwiftUI struct TestView: View { @EnvironmentObject var fetcher: TestFetcher var item: Item var isActive: Bool { fetcher.currentItemId == item.id } @State private var counter = 0 // 用AnyCancellable存储Timer的订阅 @State private var timerCancellable: AnyCancellable? var body: some View { HStack { Text("\(counter)") } .onChange(of: isActive) { newIsActive in if newIsActive { // 启动Timer:创建Timer并订阅,保存订阅对象 timerCancellable = Timer.publish(every: 1, on: .main, in: .common) .autoconnect() .sink { _ in counter += 1 } } else { // 停止Timer:取消订阅 timerCancellable?.cancel() timerCancellable = nil } } // 视图初始化时,根据初始isActive状态设置Timer .onAppear { if isActive { timerCancellable = Timer.publish(every: 1, on: .main, in: .common) .autoconnect() .sink { _ in counter += 1 } } } } }
逻辑说明
AnyCancellable管理订阅:Timer.publish返回Publisher,通过sink订阅后得到AnyCancellable,保存该对象即可控制Timer生命周期,调用cancel()就能停止Timer。.onChange监听状态变化:当isActive值改变时,根据新状态决定创建订阅Timer或取消订阅。.onAppear初始化状态:视图首次出现时,根据初始isActive状态决定是否启动Timer。
内容的提问来源于stack exchange,提问作者kindisch
相关产品推荐
相关产品推荐

