---
title: NSProgress with Asynchronous Tasks
teaser: Use NSProgress to bind your UI with the progress of asynchronous tasks.
tags: ios
author: Keith Smiley
published_on: 2015-02-06
---

NSProgress was introduced in iOS 7 and OS X 10.9 with the
[self-proclaimed][docs] purpose of being a loosely [coupled] progress
reporting mechanism. In practice this means that intermediary code
doesn't need to know anything about the progress being tracked between
the user interface layer where your application is doing work.

[docs]: https://developer.apple.com/library/prerelease/ios/documentation/Foundation/Reference/NSProgress_Class/index.html
[coupled]: http://en.wikipedia.org/wiki/Coupling_(computer_programming)

Let's see how this works in practice. In our view controller we can
setup something like this:

```objc
self.progress = [NSProgress progressWithTotalUnitCount:-1];
[self.progress becomeCurrentWithPendingUnitCount:1];
[APIClient doSomethingWithCompletion:^{
  // Asynchronous activity is done
}];

[self.progress resignCurrent];
```

Here we are creating a new `NSProgress` instance on the main thread.
Setting the `totalUnitCount` to `-1` means our progress starts with an
`indeterminate` state. In our UI we would reflect this state with a
[`UIActivityIndicatorView`] on iOS or a [`NSProgressIndicator`] with
`indeterminate` set to `YES` on OS X.

[`UIActivityIndicatorView`]: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIActivityIndicatorView_Class/index.html
[`NSProgressIndicator`]: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSProgressIndicator_Class/

Then we tell our `NSProgress` to become the current progress. Under the
hood this registers our newly created progress as the `+currentProgress`
for this thread. This becomes important when we want to create child
`NSProgress` instances elsewhere in your code which will affect this
main progress. Now we can perform some asynchronous work, and resign
from the current progress. Resigning the progress restores the previous
`NSProgress` instance where `becomeCurrentWithPendingUnitCount:` was
called. This allows us to chain multiple progress objects that are all
doing work on the same thread.

Now, in our `doSomethingWithCompletion:` implementation, no matter how
many levels deep it is, we can grab the `NSProgress` object we just
created and build off of it without explicitly passing it as an
argument. Let's look at how this may work:

```objc
- (void)doSomethingWithCompletion:(dispatch_block_t)completionBlock
{
    // Our progress instance from above
    NSProgress *mainProgress = [NSProgress currentProgress];
    // A new child progress
    NSProgress *progress = [NSProgress progressWithTotalUnitCount:-1];
    [self getObjectIDsWithCompletion:^(NSArray *IDs) {
        dispatch_async(dispatch_get_main_queue(), ^{
            mainProgress.totalUnitCount = 1;
            progress.totalUnitCount = IDs.count;
        });

        [self getEachObjectFromIDs:IDs
                         withBlock:^(NSDictionary *object) {
                            [self processObject:object];

                            dispatch_async(dispatch_get_main_queue(), ^{
                                progress.completedUnitCount++;
                            });
                      } completion:^{
                            dispatch_async(dispatch_get_main_queue(), ^{
                                progress.completedUnitCount = progress.totalUnitCount;
                                completionBlock();
                            });
                      }];
    }];
}
```

There is a lot going on here so let's step through it. We first grab the
`mainProgress` we created in our UI layer. We only need to do this
since, in this example, our progress starts off indeterminate until our
first network request has completed. We then create a new child progress
that is also indeterminate to start. Under the hood this is calling
`-initWithParent:userInfo:` on `NSProgress` and passing the
`+currentProgress` which happens to be our `mainProgress` from the UI
layer. Because of the loose coupling here, if the UI layer wasn't
utilizing this `NSProgress` chain, our networking code could look
exactly the same. The only difference is no one would be observing the
changes that are happening.

Next we fire off our first asynchronous call which gets us an array of
`IDs` of objects that we need to fetch. Now that we know how many
requests we are going to perform our `NSProgress` instances no longer
need to be indeterminate. Our `mainProgress` gets a `totalUnitCount` of
1, since the only unit of work that needs to be completed is that being
completed by our single child progress. As for the child progress, it
gets a `totalUnitCount` matching the number of requests we need to
perform. Each time one of these requests finishes, we increment the
`completedUnitCount` which is automatically reflected by our
`mainProgress`. We will look at binding this to our UI momentarily.
Finally, we call our completion block which brings us back up to the UI
layer.

At this point we have a fully functional `NSProgress` chain that we can
observe changes on and reflect in our UI.

We have many options on how to bind our `NSProgress` instance to our UI.
On OS X we could use [Cocoa Bindings]. Otherwise we could use [KVO],
possible with a [wrapper] or [ReactiveCocoa]. On OS X we can initialize
our `NSProgressIndicator` with a `minValue` and `maxValue` of `0.0` and
`1.0` respectively. This will match the behavior of [`UIProgressView`]
so that we can bind either `value` on `NSProgressIndicator` or
`progress` on `UIProgressView` to the `fractionCompleted` on
`NSProgress`. The `fractionCompleted` property uses all child progress
instances to compute an overall value for the fraction that is completed
between instances. This makes for a really accurate representation of
overall progress for multiple operations.

[Cocoa Bindings]: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/WhatAreBindings.html#//apple_ref/doc/uid/20002372-CJBEJBHH
[KVO]: http://nshipster.com/key-value-observing/
[wrapper]: https://github.com/facebook/KVOController
[ReactiveCocoa]: https://github.com/ReactiveCocoa/ReactiveCocoa
[`UIProgressView`]: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIProgressView_Class/index.html#//apple_ref/occ/instm/UIProgressView/setProgress:animated:

After setting this up we now have an awesome looking and more
informative progress indicator. Here is the indicator we've created:

![Progress Animation](https://images.thoughtbot.com/ios-nsprogress/progress.gif)

## Related reading and listening

- [The best `NSProgress` walk through around][oleb]
- [Foundation's release notes with a mention of `NSProgress`][notes]
- [An episode of Edge Cases discussing `NSProgress`][cases]

[oleb]: http://oleb.net/blog/2014/03/nsprogress/
[notes]: https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/index.html
[cases]: http://edgecasesshow.com/084-a-couple-of-maxims-a-couple-of-aphorisms.html
