Multithreading may seem esoteric and dense, but it's super important. With so many apps in the App Store, the user interface (UI) and user experience (UX) of your app will have to be as close to flawless as possible for it to stand out. You can hire a team of designers to create the most beautiful graphics for your photo filtering app, but it won't do any good if the whole app freezes without warning when a user attempts to process an image!
To that end we can use multithreading to run heavy processes off the main thread of a device, thereby ensuring the user interface doesn't stutter and the user experience is maintained.
In this lab you will fix a broken photo filter app which hangs when the user tries to apply an "antique" filter.
- When the
Antique
button is tapped, an activity indicator should be presented and animated to show the user some processing is going on. This activity indicator should stop when the image is filtered. - We also want to allow the user to continue to pan and zoom the image while the filtration occurs in the background.
- Let's add an activity indicator to our filtering app. Instead of doing this in Interface Builder, we'll add it programmatically. In the
ImageViewController
class, add a property calledantiqueButton
of typeUIActivityIndicatorView!
. - Next, after
setupViews
inviewDidLoad
, we'll create the actual view and set it up. Paste in the following lines of code:
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
activityIndicator.color = UIColor.cyanColor()
activityIndicator.center = view.center
- Here we instantiate a
UIActivityIndicatorView
object for the property we just created with the stile of.WhiteLarge
. We then tint the indicator so it fits the theme of our app, and finally align it with the main view. - If you run the app now and hit
Antique
, you'll see the activity indicator still doesn't appear. We're not done yet! TheUIActivityIndicatorView
has been created, but hasn't been added to the superview. Do this by insertingview.addSubview(activityIndicator)
into yourviewDidLoad
. This adds ouractivityIndicator
to the view controller'sview
. - The last step we need to make our
activityIndicator
visible is to call it to start. Use the following lines to start and stop the indicator, respectively:
activityIndicator.startAnimating() // Presents and starts the activity indicator
activityIndicator.stopAnimating() // Hides and stops the activity indicator
- Add just the
startAnimating
line to yourviewDidLoad
and run your app. You should see a blue spinning activity indicator! We don't want the indicator to start as soon as the app opens, though, and we don't want it to keep going after the image has been filtered. Let's move this start function call to theantiqueButtonTapped
function ahead of the call tofilterImage
. - Uh oh! If you run the app now and tap
Antique
you'll see that the activity indicator doesn't appear until after the image has finished filtering. Try to add thestopAnimating
call on theactivityIndicator
to the completion block for the call tofilterImage
. Now the indicator never shows! - It looks like the filtering process is blocking the indicator, so we'll have to move the filtering to a different thread.
- Create a new
NSOperationQueue
inantiqueButtonTapped
and set itsqualityOfService
to.UserInitiated
. Next, move into this block the call to thefilterImage
function and its completion block which prints based on the result. - Inside the completion block of the call to
filterImage
, add a new operation block on themainQueue
which will wrap the previous contents of the completion block. This ensures that whenfilterImage
has completed and returned, the activity indicator's status will be updated on the main thread. - We still need to update the
imageView
in the main thread. Look for the line infilterImage
where we print the line "Setting final result". Add amainQueue
operation block and insert the two lines where we set theimageView
'simage
tofinalResult
and returntrue
to the completion block. - Now everything should work as expected and the user will never be left hanging for a filtering process! 😉
Play around with other filters and see what you can create! Here's a list of all available CIFilters to get you started.
View Multithreading in Swift on Learn.co and start learning to code for free.