在尝试使用 Timer.scheduledTimer 的 SwiftUI 代码中获取未解析的标识符 'self'
getting unresolved identifier 'self' in SwiftUI code trying to use Timer.scheduledTimer
在 SwiftUI 中,我注意到使用一个定时器:
尝试 1 - 这并不像 get "Use of unresolved identifier '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 应用程序中包含计时器的错误信息,我'我来演示一下。
关键是将计时器放在别处并在每次触发时发布。我们可以通过添加一个 class 来轻松做到这一点,该 class 将计时器作为可绑定对象保存到我们的环境中(请注意,您需要导入 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
}
}
}
我们需要通过环境向下传递这个 class 的一个实例,所以我们修改场景委托:
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 ...
根据上面 matt 的回答,我认为可能有一个不太复杂的版本。
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").onAppear {
self.durationTimer.start()
}
您可以观察计数变量的任何变化并相应地更新视图中的文本。
如其他评论中所述,请确保计时器不会因重新创建视图的操作而意外重启。
在 SwiftUI 中,我注意到使用一个定时器:
尝试 1 - 这并不像 get "Use of unresolved identifier '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 应用程序中包含计时器的错误信息,我'我来演示一下。
关键是将计时器放在别处并在每次触发时发布。我们可以通过添加一个 class 来轻松做到这一点,该 class 将计时器作为可绑定对象保存到我们的环境中(请注意,您需要导入 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
}
}
}
我们需要通过环境向下传递这个 class 的一个实例,所以我们修改场景委托:
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 ...
根据上面 matt 的回答,我认为可能有一个不太复杂的版本。
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").onAppear {
self.durationTimer.start()
}
您可以观察计数变量的任何变化并相应地更新视图中的文本。
如其他评论中所述,请确保计时器不会因重新创建视图的操作而意外重启。