Swift - Update/Refresh Label That Displays Time

Update Label Text with Timer Values

I see a few issues:

  • The finance object goes out of scope when fireTimer() returns. It will be deallocated then. The timer will be setting a label text on a no longer existing view controller.
  • Instantiating a UIViewController with FinanceVC() 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 update dayLabel.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!

How do I refresh a labels text

Use a Notification Observer pattern

First, set up a notification to know when the app will enter the foreground state:

func sceneWillEnterForeground(_ scene: UIScene) {
NotificationCenter.default.post(name: Notification.Name("sceneWillEnterForeground"), object: nil)
}

Note: As of iOS 13, the needed function is in the SceneDelegate file and not in AppDelegate.


Next, listen for that notification and respond by adding an observer where this type of notification is needed(such as in viewDidLoad()):

NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: Notification.Name("sceneWillEnterForeground"), object: nil) 

Note: The notification name must match the one you created in the SceneDelegate.swift file.


Lastly, create the selector mentioned above. Add code that will execute in response to the willEnterForeground notification:

@objc func willEnterForeground() {
// Update your label here
}

Note: The function name here must match the selector name above.


This link is to a small app that uses the notification-observer pattern should you feel a working example would be helpful:
https://github.com/PepperoniJoe/MusicWithColor

Updating time text label each minute in WidgetKit

A possible solution is to use the time date style:

/// A style displaying only the time component for a date.
///
/// Text(event.startDate, style: .time)
///
/// Example output:
/// 11:23PM
public static let time: Text.DateStyle


  1. You need a simple Entry with a Date property:
struct SimpleEntry: TimelineEntry {
let date: Date
}

  1. Create an Entry every minute until the next midnight:
struct SimpleProvider: TimelineProvider {
...

func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
var entries = [SimpleEntry]()
let currentDate = Date()
let midnight = Calendar.current.startOfDay(for: currentDate)
let nextMidnight = Calendar.current.date(byAdding: .day, value: 1, to: midnight)!

for offset in 0 ..< 60 * 24 {
let entryDate = Calendar.current.date(byAdding: .minute, value: offset, to: midnight)!
entries.append(SimpleEntry(date: entryDate))
}

let timeline = Timeline(entries: entries, policy: .after(nextMidnight))
completion(timeline)
}
}

  1. Display the date using the time style:
struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry

var body: some View {
Text(entry.date, style: .time)
}
}

If you want to customise the date format you can use your own DateFormatter:

struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry

static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "HH:mm"
return formatter
}()

var body: some View {
Text("\(entry.date, formatter: Self.dateFormatter)")
}
}

Here is a GitHub repository with different Widget examples including the Clock Widget.

iOS Swift Update text label after 1 second

You shouldn't use the sleep() function as this will suspend the main thread and cause your app to become non-responsive. NSTimer is one way to achieve this. It will dispatch a function at a specified time in the future.

For example -

var countdown=0
var myTimer: NSTimer? = nil

override func viewDidAppear(animated: Bool) {
countdown=5
myTimer = NSTimer(timeInterval: 1.0, target: self, selector:"countDownTick", userInfo: nil, repeats: true)
countdownLabel.text = "\(countdown)"
}

func countDownTick() {
countdown--

if (countdown == 0) {
myTimer!.invalidate()
myTimer=nil
}

countdownLabel.text = "\(countdown)"
}

How update a label periodically on iOS (every second)?

The problem is that a scheduledTimer will not get called while the main thread is tracking touches. You need to schedule the timer in the main run loop.

So instead of doing

[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES];

use

NSTimer* timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

Updating label takes too long (swift)

What happens is that code is probably run on a secondary thread. Any UI changes you make should be made on the main thread. So try this:

dispatch_async(dispatch_get_main_queue()) {
// update label
}

This should update your label instantly.

Updating Label Text several times while a Button is pressed in Swift

You can run all of your long-running tasks in a background queue, and make the label updates in the main queue. The key is to call the next function only when the first is finished, or they will run in parallel, and could all update at the same time. Here's an example

func doSomething1() {
// as good a way as any to simulate a long-running process
sleep(1)
DispatchQueue.main.async {
self.myLabel.text = "Some text1"
}
DispatchQueue.global(qos: .background).async {
self.doSomething2()
}
}
func doSomething2() {
sleep(1)
DispatchQueue.main.async {
self.myLabel.text = "Some text2"
}
DispatchQueue.global(qos: .background).async {
self.doSomething3()
}
}
func doSomething3() {
sleep(1)
DispatchQueue.main.async {
self.myLabel.text = "Some text3"
}
DispatchQueue.global(qos: .background).async {
self.doSomething4()
}
}
func doSomething4() {
sleep(1)
DispatchQueue.main.async {
self.myLabel.text = "Some text4"
}
}

@IBAction func cmdDoStuff(_ sender: UIButton) {

DispatchQueue.global(qos: .background).async {
self.doSomething1()
}
}


Related Topics



Leave a reply



Submit