我正在构建一个SwiftUI应用程序,并将所有与UI相关的东西都放在一个全局可观察类UILogic中。该类本身有一个名为bp的@Published变量,其类型为BoxParameters(struct(。
我的SwiftUI视图观察这个发布的变量,它有很多组件:aspectRatio、frameWidth、xOffset、yOffset等。例如,如果我想让我的视图更宽,我只需要像这样调用setWidth((函数:
struct BoxParameters {
private(set) var frameWidth: CGFloat = 175
mutating func setWidth(newWidth: Double) {
self.frameWidth = newWidth
}
}
class UILogic: ObservableObject {
@Published var bp = BoxParameters
func doubleWidth() {
bp.setWidth(bp.frameWidth * 2)
}
}
这很好:因为它正在发生变化,所以它创建了一个新的结构实例,该实例触发@Published发送更新,并且视图会随着新的宽度而更改。
我正在努力做的是用计时器更改frameWidth(或任何其他结构变量(。假设我不想立即改变这个值,而是想通过每秒增加10次来改变它。
我的第一个猜测是直接使用计时器:
mutating func setWidth(newWidth: Double, slow: Bool = false) {
if !slow {
self.frameWidth = newWidth
} else {
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
self.frameWidth += 1
if self.frameWidth >= newWidth {
self.frameWidth = newWidth
timer.invalidate()
}
}
}
}
此代码未编译并引发错误:Escaping closure captures mutating 'self' parameter
这已经让我有点头疼了,所以我开始四处寻找解决方案:https://stackoverflow.com/a/47173607/12596719\https://developer.apple.com/forums/thread/652094\
这两个线程引发了我的问题可能最终得到解决的希望,但这并没有改变任何事情:编译器仍然在抱怨。
这个线程似乎解决了我的问题,所以我试图在我的代码中调整它(只是为了测试它是一个void函数,只会将frameWidth增加50(:
struct BoxParameters {
...
var timerLogic: TimerLogic!
class TimerLogic {
var structRef: BoxParameters!
var timer: Timer!
init(_ structRef: BoxParameters){
self.structRef = structRef;
self.timer = Timer.scheduledTimer(
timeInterval: 0.1,
target: self,
selector: #selector(timerTicked),
userInfo: nil,
repeats: true)
}
func stopTimer(){
self.timer?.invalidate()
self.structRef = nil
}
@objc private func timerTicked(){
self.structRef.timerTicked()
}
}
mutating func startTimer(){
print("Start Timer")
self.timerLogic = TimerLogic(self)
}
mutating func stopTimer() {
print("Stop Timer")
self.timerLogic.stopTimer()
self.timerLogic = nil
}
mutating func timerTicked(){
self.frameWidth += 50
print("Timer: new frame width: (self.frameWidth)")
}
}
预期行为:它将frameWidth增加了50
发生的情况:它打印出框架宽度增加了50(打印值是正确的(,但没有任何变化。但是:如果我手动调用函数timerPicked,frameWidth会按预期更改50!啊!
我认为发生的情况是,计时器在不更改实际结构的情况下更改了结构副本的frameWidth,但timerTicked函数应该更改父结构本身。(因为self.
(
有人知道解决这个问题的方法吗?将结构更改为观察到的类本来是一种选择,但由于Swift的设计,@Published类中@Published变量的更改不会通知SwiftUI更改。。。
为什么要把类和任何代码逻辑放在结构中?我认为您需要将逻辑处理成类,只需将结构用于简单的变量用法。
结构最好用于调用应用程序周围的变量。
struct AllstructFittings {
static var collectedWorks: Bool = false
static var collected: String = "notcollected"
static var failclicked: Bool = false
}
https://www.appypie.com/struct-vs-class-swift-how-to