What is… Nuke?

This article gives a quick overview of Nuke, an open source Swift framework for loading, processing, caching, displaying, and preheating images. By Rui Peres.

Leave a rating/review
Save for later
Share
Note: This is the first of a new series of articles aimed to give you a quick overview of various interesting open source libraries that are out there. Enjoy! :]

NukeThumb

Downloading and caching images efficiently has long been a challenge for iOS developers.

Objective-C has lots of popular libraries to aid in this task, such as SDWebImage, AFNetworking, DFImageManager and more. It’s taken some time for comparable Swift libraries to show up, but one of the newest is Nuke!

Nuke is an open source Swift framework for loading, processing, caching, displaying, and preheating images. It is written by Alexander Grebenyuk, an experienced developer who also wrote DFImageManager.

In this article, I’ll give you a quick overview of installing Nuke and how to use it, and then outline the situations where you might find it useful in your apps. Let’s get started!

Getting Started

Installing Nuke is easy – it supports both CocoaPods and Carthage.

CocoaPods

If you use CocoaPods, simply add the following lines to your Podfile:

pod "Nuke"
pod "Nuke-Alamofire-Plugin" # optional
pod "Nuke-AnimatedImage-Plugin" # optional

Carthage

If you use Carthage, simply add the following lines to your Cartfile:

github "kean/Nuke"
github "kean/Nuke-Alamofire-Plugin" # optional

Currently, there is no Carthage support for the Nuke-AnimatedImage-Plugin.

What Nuke Does

Nuke helps you do 6 main things:

  1. Download Images
  2. Resize Images
  3. Cache Images
  4. Process Images
  5. Deserialize and Decode Images
  6. Preheat Images

Let’s look at each in turn.

1) Download Images

The primary goal of Nuke is to make downloading and using images in your app quick, easy, and efficient.

For example, the following snippet fetches an image for you:

Nuke.taskWithURL(url) { response in
    switch response {
    case let .Success(image, responseInfo):
        //do something with your image
    case let .Failure(error):
        //handle the error case
    }
}.resume()

Here, you simply pass in an instance of NSURL then call resume. Nuke will download your image in the background and call your response closure when it’s done.

response is an enum that describes the task’s outcome either as a success or a failure. responseInfo provides useful information to the caller, such as fastResponse, which tells you if the fetched image is from the network or the cache.

Although ImageTask doesn’t descend from NSURLSessionTask, ImageTask offers similar API methods such as resume, suspend, and cancel for managing your network calls.

Note: Astute readers will notice a similarity between this and NSURLSessionTask. In Nuke’s case, you’re using ImageTask instead of NSURLSessionTask.

2) Resize Images

So far, this is no different than what you can do with NSURLSession or other networking libraries. But you can also pass some image-specific parameters to your download task, by passing an ImageRequest instead of an NSURL, as in the example below:

var imageRequest = ImageRequest(URL: imageURL)
request.targetSize = CGSize(width: 250, height: 250)
request.contentMode = .AspectFit

Nuke.taskWithRequest(request) { response in
   // Handle the response
    switch response {
    case let .Success(image, responseInfo):
        let image = image
    case let .Failure(error):
        let error = error
    }
}.resume()

This lets you specify elements such as the target size to resize the image to, and how to do so via contentMode (AspectFill or AspectFit). Nuke will download and resize the image for you in the background.

Couldn’t you just hand UIImageView a large image and let the resizing happen behind the scenes? You could do this, and UIImageView would internally resize the image depending on the the image view’s contentMode property. However, it’s better to resize the image yourself before handing it off to UIImageView so you can keep memory usage at a minimum. That’s where Nuke comes in handy.

Note: Resizing an image can be useful when you need to scale an image to fit a defined space in your view, such as a 100×100 avatar image view. It’s wasteful to pass images through to UIView that are considerably larger than what you need.

3) Cache Images

If you use Nuke, the images you download will be cached automatically. To understand how this works, check out the following quote from Nuke’s caching mechanism guide:

“Many third-party libraries are trying to reinvent caching. Nuke doesn’t, it relies on HTTP cache as defined in HTTP specification and an excellent caching implementation provided by Foundation. If you are trying to implement your own HTTP caching methodology you are probably doing it wrong.”

Rather than reinventing caching, Nuke relies on two built-in caching mechanisms offered by Apple:

  • NSURLSession‘s caching mechanism via NSURLCache
  • NSCache

NSURLSession provides both disk and in-memory caching; it’s controlled primarily by the HTTP headers sent back in response to your request. NSCache is an in-memory cache that sits on top of the URL loading framework’s caching mechanism to make things even faster.

The added benefit of using NSURLCache is that it’s completely transparent to the user. After requesting an image, you can verify its existence in the cache by checking the default NSURLCache singleton like so:

let cachedResponse = NSURLCache.sharedURLCache().cachedResponseForRequest(imageRequest)

4) Process Images

Besides downloading and caching the image, ImageRequest also allows you define custom filters to apply to the fetched image. Yes, you could technically do this by yourself, but it’s still a nice touch.

The code below shows how easy it can be to add a blur effect to your retrieved image:

let blurringImageFilter : ImageProcessing = MyFilters.blurringFilter()

var imageRequest = ImageRequest(URL: imageURL)
imageRequest.processor = blurringImageFilter

Nuke.taskWithRequest(request) { response in
    switch response {
    // Handle the response
    case let .Success(image, responseInfo):
        let image = image
    case let .Failure(error):
        let error = error
    }
}.resume()

The key element in the code above is Nuke’s ImageProcessing protocol. It defines several methods you must comply with; the most important one is this:

func processImage(image: UIImage) -> UIImage?

You pass this method an instance of UIImage and it returns an UIImage optional. If the filter operation succeeds, you get a new image with the filter already applied. If Nuke can’t apply the filter for whatever reason, it returns nil. It’s quite straightforward!

5) Deserialize & Decode Images

Once you request an image from the network, there are two things that must happen before iOS can display it on the screen: image deserialization, and image decoding.

Image Deserialization

The first is image deserialization, which translates a binary blob to the image file.

UIImage can handle deserialization for you, but this potentially expensive operation usually happens on the main thread and can affect your UI. Nuke helps you maintain a buttery smooth UI by handling deserialization in the background. This occurs in Nuke’s ImageDecoder class, with the important bit as follows:

return UIImage(data: data, scale: UIScreen.mainScreen().scale)

Note: There isn’t anything in Apple’s official documentation stating init?(data data: NSData, scale scale: CGFloat) is thread-safe. Nevertheless, from an empirical point of view, and mostly agreed upon in the development community at large, init?(data data: NSData, scale scale: CGFloat) works outside the main thread.

Image Decoding

The step after deserialization is image decoding. An image always comes to you encoded in a particular image format, usually denoted by the file’s extension, such as .JPG or .PNG. Image decoding takes the encoded file and uses image standards to translate the file into a 2-D grid of colors to show on the screen.

The good news is that UIImage and UIImageView handle image decoding for you automatically. The bad news is that, like deserialization, decoding usually happens on the main thread, which again can degrade UI performance.

Nuke handles image decoding off the main thread as well. Nuke’s ImageDecompressor class internally forces early decompression into a Core Graphics context in the background. Very cool! :]

Rui Peres

Contributors

Rui Peres

Author

Over 300 content creators. Join our team.