We all enjoy fast and responsive apps that feel good when you use them. Therefore as iOS developers we spend a lot of time on delivering the best possible experience to the user. This becomes extra important when your application has to perform some long running operation, for example downloading a large video. Depending on the size of the download, speed of the user’s internet connection, or hardware this could take a while, which can be frustrating for the user. We can improve such an experience by giving the user a sense of the current work that is happening and how far that work has progressed by using a progress indicator.
Lately I have discovered the
Progress class from Foundation which allows us to do just that. This weeks blogpost will show you the basics of
Progress by taking you through an example of how to show the progress of downloading an image to the user.
Progress is a class that represents the completion of some work that an application is doing for example downloading or uploading a file to the server.
Many of the api’s that we use on a daily basis report their progress with
Progress for example
NSURLSession which we get to later in this blogpost. Of course you can also use
Progress to report progress from the custom components in your application and if the work your application is doing consists of multiple sub steps you can even use composition to create a tree of progress objects.
The basics of
Progress has three important properties that you should know about:
Let’s have a look at each one of them.
totalUnitCount represents how many units of work a
Progress object should track, for example the amount of bytes of a download.
completedUnitCount reports how much work of the total amount of work that the progress tracks has completed.
fractionCompleted tells you how much of the work has completed. It is a double value between 0 and 1 where 0 means that none of the work has completed and 1 means that all the work has completed.
Progress also has a property called
localizedAdditionalDescription which can be used to provide the user with more information on what is happening in your application. Through the
kind property you can tell the progress object what its unit represents and to format the progress as such, for example if you set it to
localizedAdditionalDescription gives you a byte formatted string.
In this example we are going to download an image from the internet and display the progress to the user. Download the sample project if you want to follow along with this example.
The example project has one view controller which is very simple. It contains an
UIImageView for showing the downloaded image, a
UIButton to trigger a download, two
UILabels that will contain text to explain the user what’s going. It also contains a
UIProgressView which is a view that displays the progress in a progress bar.
Our view controller also has a reference to an
ImageDownloader which has a method
downloadImage(with:completion:) that downloads the image from the passed in
URL This method returns a progress object which we will use to update our UI and has a completion handler with an optional image that gets called once the download has finished.
downloadImage(with:completion) method we create a
URLSessionDownloadTask with the passed in url of the image. Since iOS 11 a task has a property called
progress that contains the tasks progress object which we can use to update our UI.
When a download action is triggered we call the download function and store the returned progress object in a property called
downloadProgress in our view controller. It has a property observer in which we attach the new progress object to the UI. To display the progress in our progress view we set
downloadProgress to the
observedProgress property of the view. We use KVO to update our progress label every time the
localizedAdditionalDescription changes. KVO notifications of properties on
Progress are sent from the thread on which the progress was updated and therefore we have to dispatch our update of the progress label onto the main queue to make sure our UI gets updated on the main thread.
Next time when your application is performing some long running task consider using
Progress to let the user know what is happening in the application. As you can see from the example some Cocoa api’s already support progress reporting and therefore just require a few steps to make it work. But there is much more you can do with
Progress. You could for example create a tree of progress objects or use the progress object to cancel, pause or resume work. Take a look at it and have some fun!
Contact me on Twitter @kairadiagne if you have any questions, comments or feedback.