SwiftUI中Timer无需@State即可工作的原因解析
SwiftUI中Timer相关疑问解答
1. 每次视图重绘时是否会创建新的Timer发布者?
得看你怎么声明Timer:
- 要是直接在View结构体里写
let timer = Timer.publish(...),因为SwiftUI视图是值类型,每次状态变化导致视图结构体重建(也就是重绘),都会生成新的Timer发布者。 - 但正确的写法一般是把Timer声明成静态常量(比如
static let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()),静态属性属于视图类型本身,只会初始化一次,不管视图重绘多少次,都不会新建发布者。 - 另外,把Timer放到
@StateObject或者ObservableObject管理的ViewModel里也行,ViewModel实例会被持久化,不会跟着视图重绘换新的,Timer自然也不会重复创建。
2. 为何这类需要持久化的Timer对象无需使用@State?
- 如果是静态常量的Timer,它的生命周期和视图类型绑死了,跟单个视图实例活不活没关系,根本不需要
@State来帮它保状态。 - 要是把Timer放在ViewModel里,ViewModel由
@StateObject持有,@StateObject会确保ViewModel在视图整个生命周期里只有一个实例,Timer作为ViewModel的属性,跟着ViewModel一起持久化,也不用额外加@State。 - 而且
Timer.publish返回的是发布者,它的订阅生命周期是由SwiftUI的onReceive这类修饰符自动管的,不需要用@State存状态。
3. 执行timer.upstream.connect().cancel()取消Timer后,视图重绘时为何不会重置重启?
Timer.publish是冷发布者,只有调用connect()才会开始计时。你调用cancel()之后,这个发布者的连接就断了,计时也就停了。- 如果Timer是静态常量,整个App里就这一个实例,视图重绘时用的还是这个已经被取消的发布者,它不会自己重新初始化或者重启,除非你手动再调用一次
connect()。 - 就算你用了
.autoconnect(),它的自动连接逻辑只在第一次订阅的时候触发,一旦你手动取消了上游连接,发布者已经处于终止状态了,视图重绘也不会让它重新连接。
内容的提问来源于stack exchange,提问作者Andres Riofrio
相关产品推荐
相关产品推荐

