swift - 在尝试使用 Timer.scheduledTimer 的 SwiftUI 代码中获取未解析的标识符 'self'

标签 swift swiftui swift5

在 SwiftUI 中,我注意到使用一个 Timer:

尝试 1 - 这不起作用,因为“使用未解析的标识符‘self’”

var timer2: Timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {
    self.angle = self.angle + .degrees(1)
}

尝试 2 - 有效,但必须放入“_ = self.timer”才能稍后启动

var timer: Timer {
    Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) {_ in
        self.angle = self.angle + .degrees(1)
    }
}
// then after need to use " .onAppear(perform: {_ = self.timer}) "

有没有办法让我的 Try1 工作?那是我可以在 SwiftUI 文件中预先创建计时器的地方?或者实际上在 SwiftUI 的什么地方通常会启动和停止计时器?即生命周期方法在哪里

整个文件:

import SwiftUI

struct ContentView : View {

    @State var angle: Angle = .degrees(55)

//    var timer2: Timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {
//        self.angle = self.angle + .degrees(1)
//    }

    var timer: Timer {
        Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) {_ in
            self.angle = self.angle + .degrees(1)
        }
    }

    private func buttonAction() {
        print("test")
        self.angle = self.angle + .degrees(5)
    }

    var body: some View {
        VStack{
            Text("Start")
            ZStack {
                Circle()
                    .fill(Color.blue)
                    .frame(
                        width: .init(integerLiteral: 100),
                        height: .init(integerLiteral: 100)
                    )
                Rectangle()
                    .fill(Color.green)
                    .frame(width: 20, height: 100)
                    // .rotationEffect(Angle(degrees: 25.0))
                    .rotationEffect(self.angle)
            }
            Button(action: self.buttonAction) {
                Text("CLICK HERE")
            }
            Text("End")
        }
         .onAppear(perform: {_ = self.timer})

    }
}

最佳答案

我不清楚您的示例是否需要计时器,但由于存在大量关于如何在 SwiftUI 应用程序中包含计时器的错误信息,我将进行演示。

关键是将计时器放在别处并在每次触发时发布。我们可以通过添加一个将计时器作为可绑定(bind)对象保存到我们的环境中的类来轻松地做到这一点(请注意,您将需要导入 Combine):

class TimerHolder : BindableObject {
    var timer : Timer!
    let didChange = PassthroughSubject<TimerHolder,Never>()
    var count = 0 {
        didSet {
            self.didChange.send(self)
        }
    }
    func start() {
        self.timer?.invalidate()
        self.count = 0
        self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { 
            [weak self] _ in
            guard let self = self else { return }
            self.count += 1
        }
    }
}

我们需要通过环境向下传递这个类的一个实例,所以我们修改场景委托(delegate):

window.rootViewController = 
    UIHostingController(rootView: ContentView())

成为

window.rootViewController = 
    UIHostingController(rootView: ContentView()
        .environmentObject(TimerHolder()))

最后,让我们建立一些启动计时器并显示计数的 UI,以证明它正在工作:

struct ContentView : View {
    @EnvironmentObject var timerHolder : TimerHolder
    var body: some View {
        VStack {
            Button("Start Timer") { self.timerHolder.start() }
            Text(String(self.timerHolder.count))
        }
    }
}

编辑 为那些没有关注情节的人更新:BindableObject 已经迁移到 ObservableObject,不再需要手动信号。所以:

class TimerHolder : ObservableObject {
    var timer : Timer!
    @Published var count = 0
    // ... and the rest is as before ...

关于swift - 在尝试使用 Timer.scheduledTimer 的 SwiftUI 代码中获取未解析的标识符 'self',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56895459/

相关文章:

ios - swift/iOS 中的方格纸交互

ios - 在 UIMenuController iOS 开头追加自定义 UIMenuItems

ios - 结构转换为 xml (Swift)

ios - 具有两个 View 的 SwiftUI Card Flip 动画,其中一个嵌入在 Stack 中

ios - 如何在 SwiftUI 中使用 "*.scnp"文件进行按钮单击(iOS)?

swift - 如何使用 lookAtConstraint 获取节点的方向

swiftui - 我们如何在 SwiftUI 中延迟加载数据到表单/列表?

swift - 如何禁用 NSView 上的鼠标单击和鼠标拖动?

ios - 是否可以更改状态栏高度/y 位置?

swift - Xcode 10.2 将多个目标转换为 Swift 5 : Tries to compile some classes that are not part of target