HiveBrain v1.2.0
Get Started
← Back to all entries
patternswiftMinor

Timer UI-updating implementation for educational purposes

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
updatingeducationaltimerforimplementationpurposes

Problem

I thought it would be helpful to put together an example of what I'm talking about in the second part of my answer to this Stack Overflow question.

The idea is that there's some data that is updated very quickly (i.e. faster than the main queue can reasonably process blocks) on a background thread that needs to be displayed in a UI (in this code, a counter in a while loop). Instead of trying to update the UI at the same rate that the data is updated, a timer is setup on the main thread which fires off a method updating the UI every 0.1 seconds or so. Also taken in to account is the need for data synchronization between the writes on the background thread and the reads on the main thread. All threading and data synchronization is handled using Grand Central Dispatch.

My intent with this code is mainly to help teach someone how to go about this without a separate writeup explaining the code; it's meant to accompany the explanation of the concept in my answer. With that in mind, I put in a ton of comments attempting to explain what I'm doing and why I'm doing it, even when it seemed obvious. However, I tried to not repeat myself. Since this is written in Swift and the language is very new, there are also some comments explaining some things that need to be considered for Swift specifically.

What I'm looking for is just a general code review, keeping in mind that the code and comments are intended to try to help teach someone how to implement this concept.

```
@IBOutlet weak var dataTextField: NSTextField!
@IBOutlet weak var countTextField: NSTextField!

var data: UInt64 = 0
var uiUpdateCount: UInt64 = 0
var uiUpdateTimer: NSTimer? = nil

/*
How often to update the UI, in seconds.

Feel free to play with this value and see what happens,
even 0.01 (~1/60th of a second) only uses ~4% CPU for
the UI thread on my machine.
*/
var updateInterval: NSTimeInterval = 0.1

// Create a serial queue for synchronized data access
let dataAccessQueue = dispatch

Solution

I don't think this code is very good teaching code.

First of all, I personally prefer using NSOperationQueue for this sort of stuff. My guess is that people completely uncomfortable with asynchronous code will be also. NSOperationQueue code looks just like all your other Objective-C/Swift stuff. Yes, GCD definitely has its advantages, but it just doesn't quite fit in (from an appearance standpoint) with all the other rest of the code. I think people who need a tutorial instead of just reading documentation are more likely going to want something that looks comfortable and familiar.

Second... I don't like the idea that someone would be taught that there should be no synchronization between data updates and UI updates. Yes, your code does manage to update the UI on the main thread, and it does manage to update the data in the background thread.

But they each do this completely independently. It's nothing special. And you're right, even updating at 10 milliseconds, you don't use that much processing power.

But any time you update the UI when the data hasn't updated, you've wasted time on the processor. May not be a big deal, and in this case, it's definitely not, but this is an extraordinarily simplistic case.

Moreover, any time you update the data and don't immediately update the UI to reflect that change in data, your UI is behind.

The more correct way to handle this sort of stuff, in my opinion, isn't to have a looping updater that refreshes your entire UI every 10ms (consider a more complicated view with several more elements to update).

Just as we can from the main thread put code to run on a background thread, from a background thread, we can add code to the main queue. The appropriate approach then can only logically be to dispatch the UI update onto the main thread from the background thread when new data has actually been received.

We can use dispatch_async(dispatch_get_main_queue()) from a background thread to queue up executable code onto the main thread.

(Or, if we opt for NSOperationQueue's, we can call the mainQueue() method to get a reference to the main queue and add operations to it.)

Context

StackExchange Code Review Q#61127, answer score: 3

Revisions (0)

No revisions yet.