SwiftUI在视图更新阶段,如果尝试修改@Published / @StateObject / @ObservedObject 所管理的状态,就会弹出警告提示。
例如,Swift代码:
class CustomImages: ObservableObject {
@Published var inputURL: URL // 输入URL
@Published private var _inputSize: Int? // 文件输出大小
// 输入文件的大小
var inputSize: Int {
if _inputSize == nil {
_inputSize = FileUtils.getFileSize(fileURL: inputURL) // 报错代码行
}
return _inputSize ?? 0
}
}
这个类中,inputSize是一个计算属性,如果 inputSize 变量为nil,就会计算输入文件的大小,并赋值给 _inputSize 变量。
但是,Xcode在赋值代码行中会提示:
Publishing changes from within view updates is not allowed, this will cause undefined behavior.
因为,SwiftUI 明确禁止,在视图更新过程中发布状态变更。因此产生这个提示信息。
计算属性应该是纯函数(无副作用),如果涉及读取状态、计算I/O、修改状态(触发objectWillChange),就会破坏SwiftUI的渲染事物一致性,导致无限刷新、状态错乱以及UI Bug等问题。
解决方案
1、懒加载逻辑移除计算属性
将计算属性中的修改属性状态代码改为方法,在SwiftUI中调用方法。
func loadInputSizeIfNeeded() {
guard _inputSize == nil else { return }
_inputSize = FileUtils.getFileSize(fileURL: inputURL)
}
// SwiftUI 中显示
.onAppear {
image.loadInputSizeIfNeeded()
}
计算属性,仅用于读取数据:
var inputSize: Int {
return _inputSize ?? 0
}
2、使用 lazy
lazy var inputSize: Int = {
FileUtils.getFileSize(fileURL: inputURL)
}()
lazy 不适用于 SwiftUI 状态对象,这里并不适用。
