SwiftUI with a Timer

huangapple go评论157阅读模式
英文:

SwiftUI with a Timer

问题

I am new to learning SwiftUI, I want to add a Timer to a VIEW in SwiftUI, why can't I update "SomeTEXTinVIEW", what error do I not understand, how can I update an @State variable that is not inside Colsure?

Cannot use instance member 'SomeTEXTinVIEW' within property initializer; property initializers run before 'self' is available

    @State var SomeTEXTinVIEW: String = "NoValue"
    
    var timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
        
        SomeTEXTinVIEW = String("Example Result")  // With Error, can not update
        
    }

....

FOLLOW UP ....

I originally planned that the Timer could be paused. I changed the Code suggested by Marcy, but there was an error. Please tell me where I went wrong. Thanks in advance for help.

    struct ContentView: View {
    @State var someTextInView: Int = 0
    
    var timer = Timer()  // Comment this line !!!
    @State var timer = Timer()
    
    var body: some View {
        VStack {
            Text(String(someTextInView))
            
            Button("Re-Start", action: {
                timer.fireDate = Date.init(timeIntervalSinceNow: 0.01)})
            
            Button("Pause / Stop", action: {
                timer.fireDate = Date.distantFuture
                timer.invalidate()  // Comment this line !!!
            })
        }
        .onAppear {
            timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                someTextInView += 1
            }
        }
    }
}

The following is executable without errors (Just for references)

    struct ContentView: View {
    @State var someTextInView: Int = 0
    
    var body: some View {
            Text(String(someTextInView))
        .onAppear {
            Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                someTextInView += 1
            }
        }
    }
}
英文:

I am new to learning SwiftUI, I want to add a Timer to a VIEW in SwiftUI, why can't I update "SomeTEXTinVIEW", what error do I not understand, how can I update an @State variable that is not inside Colsure ?

Cannot use instance member 'SomeTEXTinVIEW' within property initializer; property initializers run before 'self' is available

    @State var SomeTEXTinVIEW: String = "NoValue"
    
    var timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
        
        SomeTEXTinVIEW = String("Example Result")  // With Error, can not update
        
    }

.... FOLLOW UP ....

I originally planned that the Timer could be paused. I changed the Code suggested by Marcy, but there was an error. Please tell me where I went wrong. Thanks in advance for help.

    struct ContentView: View {
    @State var someTextInView: Int = 0
    
    var timer = Timer()  // Comment this line !!!
    @State var timer = Timer()
    
    var body: some View {
        VStack {
            Text(String(someTextInView))
            
            Button("Re-Start", action: {
                timer.fireDate = Date.init(timeIntervalSinceNow: 0.01)})

            Button("Pause / Stop", action: {
                timer.fireDate = Date.distantFuture
                timer.invalidate()  // Comment this line !!!
            })
        }
        .onAppear {
            timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                someTextInView += 1
            }
        }
    }
}

The following is executable without errors (Just for references)

    struct ContentView: View {
    @State var someTextInView: Int = 0
    
    var body: some View {
            Text(String(someTextInView))
        .onAppear {
            Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                someTextInView += 1
            }
        }
    }
}

答案1

得分: 1

Finally, I found the solution in different tests by myself, but I don't know if it is correct, can anyone inform me? Or tell me the correct way

struct ContentView: View {
    
    @State var someTextInView: Int = 0
    
    static var timer = Timer()
    
    var body: some View {
        VStack {
            Text(String(someTextInView))
            
            Button("Re-Start", action: {
                ContentView.timer.fireDate = Date.init(timeIntervalSinceNow: 0.01)
            })
            
            Button("Pause", action: {
                ContentView.timer.fireDate = Date.distantFuture
            })
        }
        .onAppear {
            ContentView.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                someTextInView += 1
            }
        }
    }
}

There is a feeling that I may be wrong, that is a lot of "ContentViews" are added.

英文:

Finally, I found the solution in different tests by myself, but I don't know if it is correct, can anyone inform me? Or tell me the correct way

    struct ContentView: View {
    
    @State var someTextInView: Int = 0
    
    static var timer = Timer()
    
    var body: some View {
        VStack {
            Text(String(someTextInView))
            
            Button("Re-Start", action: {
                ContentView.timer.fireDate = Date.init(timeIntervalSinceNow: 0.01)})
            
            Button("Pause", action: {
                ContentView.timer.fireDate = Date.distantFuture
            })
        }
        .onAppear {
            ContentView.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                someTextInView += 1
            }
        }
    }
}

There is a feeling that I may be wrong, that is a lot of "ContentViews" are added.

答案2

得分: 0

以下是翻译好的部分:

错误信息如下:

在属性初始化程序内无法使用实例成员“SomeTEXTinVIEW”;属性初始化程序在“self”可用之前运行

定时器属性无法使用SomeTEXTinVIEW,因为它尚未创建。结构体(以及类和枚举)是属性和方法的无序列表。因此,在这种情况下,结构体的属性声明不能依赖于结构体的另一个属性的存在。

但是可以像这样执行定时器:

struct ContentView: View {
    @State var someTextInView: String = "NoValue"
    
    var body: some View {
        Text(someTextInView)
        .onAppear {
            Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
                someTextInView = "Example Result"
            }
        }
    }
}

我建议将属性SomeTEXTinVIEW改写为驼峰式命名,就像这样someTextInView。这是Swift中接受的风格,有助于使代码更易于阅读,因为它有助于区分属性和类型。

将"Example Result"转换为字符串是不必要的,因为它已经是一个字符串。

英文:

The error generated is:

Cannot use instance member 'SomeTEXTinVIEW' within property initializer; property initializers run before 'self' is available

The timer property can't use SomeTEXTinVIEW because it hasn't been created yet. Structs(and classes and enums) are unordered lists of properties and methods. So the struct's property declarations can't rely on the existence of another of the struct's properties in that situation.

But the timer could be executed something like this instead:

struct ContentView: View {
	@State var someTextInView: String = "NoValue"
	
	var body: some View {
		Text(someTextInView)
		.onAppear {
			Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
				someTextInView = "Example Result"
			}
		}
	}
}

I'd recommend that the property SomeTEXTinVIEW be written in camel case like this someTextInView. That's the accepted style in Swift and will makes the code easier to read as it helps to distinguish properties from types.

Converting "Example Result" to a string is unnecessary because it is already a string.

答案3

得分: 0

I have created an extension for me to have an easy way to use Timer in SwiftUI.

Extensions:

import Foundation
import Combine

@available(macOS 10.15, *)
public func TimerPublisher(every: CGFloat) -> Publishers.Autoconnect<Timer.TimerPublisher> {
    Timer.publish(every: every, on: .main, in: .common).autoconnect()
}

@available(macOS 10.15, *)
public extension Publishers.Autoconnect where Upstream == Timer.TimerPublisher {
    func stopTimerPublisher() {
        self.upstream.connect().cancel()
    }
}

Usage:

struct ContentView: View {
    @State var someTextInView: String = "NoValue"

    var timer = TimerPublisher(every: 1.5)
    
    var body: some View {
        Text(someTextInView)
            .onReceive(timer) { _ in
                 someTextInView += "Hello "
             }
    }
}

And if you need to stop the timer, all you need is:

timer.stopTimerPublisher()
英文:

I have create extension for me to have easy way to use Timer in SwiftUI

Extensions:

import Foundation
import Combine

@available(macOS 10.15, *)
public func TimerPublisher(every: CGFloat) -&gt; Publishers.Autoconnect&lt;Timer.TimerPublisher&gt; {
    Timer.publish(every: every, on: .main, in: .common).autoconnect()
}

@available(macOS 10.15, *)
public extension Publishers.Autoconnect where Upstream == Timer.TimerPublisher {
    func stopTimerPublisher() {
        self.upstream.connect().cancel()
    }
}

usage:

struct ContentView: View {
    @State var someTextInView: String = &quot;NoValue&quot;

    var timer = TimerPublisher(every: 1.5)
    
    var body: some View {
        Text(someTextInView)
            .onReceive(timer) { _ in
                 someTextInView += &quot;Hello &quot;
             }
    }
}

and if you need to stop timer, all you need is:

timer.stopTimerPublisher()

huangapple
  • 本文由 发表于 2023年3月12日 10:22:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75710741.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定