How to update text using timer in SwiftUI
i have managed to update text using alert.
i have declared date as State
so whenever date is changed using alert text will also get updated.
struct CurrentDateView : View {
@State var newDate = Date()
let timer = Timer.publish(every: 1, on: .current, in: .common).autoconnect()
var body: some View {
Text("\(newDate)")
.onReceive(timer) {
self.newDate = Date()
}
}
}
SwiftUI - Timer to update text
You can try using SwiftUI formatting features vs using String
import SwiftUI
import Combine
struct WorldTimerView: View {
@StateObject var timers = TimerData()
//Use TimeZone directly
@State var timezones: [TimeZone] = [TimeZone.current, TimeZone(identifier: "America/Halifax")!]
var body: some View {
List {
ForEach(timezones, id: \.self) { timeZone in
Text(timers.date, formatter: formatter)
//Inject the TimeZone to the Text
.environment(\.timeZone, timeZone)
//You can also use style
Text(timers.date, style: .time).environment(\.timeZone, timeZone)
}
}
}
var formatter: DateFormatter{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "h:mm:ss a"
return dateFormatter
}
}
Update Label Text with Timer Values
I see a few issues:
- The
finance
object goes out of scope whenfireTimer()
returns. It will be deallocated then. The timer will be setting a label text on a no longer existing view controller. - Instantiating a
UIViewController
withFinanceVC()
doesn't display it on screen. After instantiating you need to explicitly show. You can do this for example by calling present(_:animated:completion:) from a parent view controller. - The timer updates
dayLabelText
which does not updatedayLabel.text
Might be good to follow a basic YT tutorial on how to display a view controller.
Good luck, you'll get it soon enough!
SwiftUI update Textlabel from Background Timer
Change your body
to.
var body: some View {
VStack {
Text("\(timeLeft)")
Button(action: {
self.start.toggle()
self.notifyTime = Date().addingTimeInterval(TimeInterval(10)) // add countdown time in sec
self.timeLeft = timeDifference(endTime: self.notifyTime)
self.sendNotification()
//Timer code - Start your timer
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
timeLeft -= 1
if timeLeft == 0 {
timer.invalidate()
//Add your new trigger event
}
}
}) { Text("Start Countdown (10s)")}
}.onAppear(perform: {
UNUserNotificationCenter.current().requestAuthorization(options: [.badge,.sound,.alert]) { (_, _) in
}
})
}
SwiftUI: Updating Model with a timer and reflecting it in UI
I wouldn't rely on a mutating
member of the struct
to project the changes to the @Published
wrapper. I'd use something that explicitly gets/sets the model.
This, for example, works:
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
Text(viewModel.number)
}
}
class ViewModel: ObservableObject, HeartbeatModifier {
@Published private var model = Model()
var emitter = HeartbeatEmitter()
init() {
emitter.delegate = self
}
func beat() {
model.number += 1
}
var number: String {
"\(model.number)"
}
}
protocol HeartbeatModifier {
func beat()
}
protocol Heartbeat {
var number : Int { get set }
}
struct Model: Heartbeat {
var number: Int = 0
}
class HeartbeatEmitter {
private var timer: Timer!
var delegate: HeartbeatModifier?
init() {
setupTimer()
}
func setupTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(notifyDelegate), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: .common)
}
@objc
func notifyDelegate() {
delegate?.beat()
}
}
SwiftUI Timer.publish causing whole screen to refresh
If you want to refresh only a part of body, then separate that part into dedicated subview, eg:
struct ApptCardView: View {
@ObservedObject var apptCardVM: ApptCardViewModel
var body: some View {
VStack {
CurrentDateView() // << here !!
Picker("Seizure Type", selection: $apptCardVM.typeIndex) {
ForEach(0..<apptCardVM.typeChoice.count) {
Text(self.apptCardVM.typeChoice[$0])
}
}.pickerStyle(SegmentedPickerStyle())
}
}
}
struct CurrentDateView: View {
@State private var currentDate = Date()
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Text("\(currentDate)")
.onReceive(timer) { input in
self.currentDate = input // << refresh only own body !!
}
}
}
Related Topics
How to Retrieve a Random Object from Firebase Using a Sequential Id
Swift Parsing Attribute Name for Given Elementname
Uiscrollview with Embedded Uiimageview; How to Get the Image to Fill the Screen
Missing Return in a Function Expected to Return 'Double'
Macos Menubar Application: Main Menu Not Being Displayed
How to Open a Nspopover at a Distance from the System Bar
Getting Dyld_Fatal_Error After Updating to Xcode 6 Beta 4 Using Swift
Custom Swift Encoder/Decoder for the Strings Resource Format
How to Detect Vertical Planes in Arkit
Implicitly Lazy Static Members in Swift
Get the Last Character of a String Without Using Array
Swiftui Hide Tabbar in Subview
How to Avoid Nested Navigation Bars in Swiftui
Difference Between String Interpolation and String Initializer in Swift