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

时间:2019-07-05 01:08:27

标签: swift swiftui swift5

在SwiftUI中,我要使用一个计时器:

尝试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})

    }
}

2 个答案:

答案 0 :(得分:1)

对于我来说尚不清楚您需要为示例使用计时器,但是由于那里存在大量关于如何在SwiftUI应用程序中包含计时器的错误信息,因此我将进行演示。

关键是将计时器放在其他位置,并在每次触发时进行发布。我们可以通过在我们的环境中添加一个将计时器作为可绑定对象的类来轻松地做到这一点(请注意,您将需要导入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) { 
            _ in
            self.count += 1
        }
    }
}

我们将需要在环境中传递此类的实例,因此我们修改了场景委托:

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))
        }
    }
}

答案 1 :(得分:0)

基于上述马特的答案,我认为有一种不太复杂的版本。

class TimerHolder : ObservableObject {
var timer : Timer!
@Published var count = 0
func start() {
    self.timer?.invalidate()
    self.count = 0
    self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {
        _ in
        self.count += 1
        print(self.count)
    }
}

}

使用: ObservableObject@Publish var count

和在视图中

@ObservedObject var durationTimer = TimerHolder()
...
Text("\(durationTimer.count) Seconds")

您可以观察到count变量的任何变化,并相应地更新视图中的Text。

如其他注释中所述,请确保计时器不会由于重新创建视图的动作而意外重启。