Loading, processing, caching and preheating images. To get started check out http://kean.github.io/Nuke
var request = ImageRequest(URL: NSURL(string: "http://..."))
request.targetSize = CGSize(width: 200, height: 200) // Resize image
request.processor = ImageFilterGaussianBlur() // Apply image filter
Nuke.taskWith(request) { response in
let image = response.image
}.resume()
- User-friendly API, zero configuration required
- Performant, asynchronous, thread safe
- Nuke is a pipeline with injectable dependencies
- Alamofire and FLAnimatedImage plugins
- Extensions for UI components
- Two cache layers including auto purging memory cache
- Protocol for integrating any third-party caching library
- Automates image preheating (precaching)
- Create, compose and apply image filters
- Background image decompression
- Simple Core Image integration
- iOS 8.0+ / watchOS 2.0+ / OS X 10.9+ / tvOS 9.0+
- Xcode 7.3+, Swift 2.2+
- Best place to get started is http://kean.github.io/Nuke
- Get a demo project using
pod try Nuke
command - Experiment with Nuke in a playground
- Install and
import Nuke
Loading an image is as simple as creating and resuming an ImageTask
. Nuke is thread safe, you can freely create and resume tasks from any thread. The completion closure is called on the main thread.
Nuke.taskWith(NSURL(URL: "http://...")!) {
let image = $0.image
}.resume()
Each ImageTask
is created with an ImageRequest
which contains request parameters. An ImageRequest
can be initialized either with NSURL
or NSURLRequest
.
var request = ImageRequest(URLRequest: NSURLRequest(NSURL(URL: "http://...")!))
// Set target size (in pixels) and content mode that describe how to resize loaded image
request.targetSize = CGSize(width: 300.0, height: 400.0)
request.contentMode = .AspectFill
// Set filter (more on filters later)
request.processor = ImageFilterGaussianBlur()
// Control memory caching
request.memoryCacheStorageAllowed = true // true is default
request.memoryCachePolicy = .ReloadIgnoringCachedImage // Force reload
// Change the priority of the underlying NSURLSessionTask
request.priority = NSURLSessionTaskPriorityHigh
Nuke.taskWith(request) {
// - Image is resized to fill target size
// - Blur filter is applied
let image = $0.image
}.resume()
Processed images are stored into memory cache. Next time you start the same request the completion will be called synchronously.
The response passed into the completion closure is represented by an ImageResponse
enum. It has two states: Success
and Failure
. Each state has some values associated with it.
Nuke.taskWith(request) { response in
switch response {
case let .Success(image, info):
if (info.isFastResponse) {
// Image was returned from the memory cache
}
case let .Failure(error):
// Handle error
}
}.resume()
ImageTask
is your primary interface for controlling the image load. Task is always in one of four states: Suspended
, Running
, Cancelled
or Completed
. The task is always created in a Suspended
state. You can use the corresponding resume()
and cancel()
methods to control the task's state. It's always safe to call these methods, no matter in which state the task is currently in.
let task = Nuke.taskWith(imageURL).resume()
print(task.state) // Prints "Running"
// Cancels the image load, task completes with an error ImageManagerErrorCode.Cancelled
task.cancel()
You can also use ImageTask
to monitor load progress.
let task = Nuke.taskWith(imageURL).resume()
print(task.progress) // The initial progress is (completed: 0, total: 0)
// Add progress handler which gets called periodically on the main thread
task.progressHandler = { progress in
// Update progress
}
// Task represents an image promise
// It allows you to add multiple completion handlers, even when the task is completed
task.completion {
let image = $0.image
}
Nuke provides UI extensions to make image loading as simple as possible.
let imageView = UIImageView()
// Loads and displays an image for the given URL
// Previously started requests are cancelled
let task = imageView.nk_setImageWith(NSURL(URL: "http://...")!)
// let task = imageView.nk_setImageWith(ImageRequest(...))
You have extra control over loading via ImageViewLoadingOptions
. If allows you to provide custom animations
, override the completion handler
, etc.
let imageView = UIImageView()
let request = ImageRequest(URLRequest: NSURLRequest(NSURL(URL: "http://...")!))
var options = ImageViewLoadingOptions()
options.handler = {
// The `ImageViewLoading` protocol controls the task
// You handle its completion
}
let task = imageView.nk_setImageWith(request, options: )
Nuke makes it extremely easy to add image loading extensions to custom UI components. Those methods are provided by ImageLoadingView
protocol. This protocol is actually a trait - most of methods are already implemented. All you need is to implement one required method to make your custom views conform to ImageLoadingView
protocol.
You can do so by either implementing ImageDisplayingView
protocol:
extension MKAnnotationView: ImageDisplayingView, ImageLoadingView {
// That's it, you get default implementation of all methods in ImageLoadingView protocol
public func nk_displayImage(image: Image?) {
self.image = image
}
}
Or providing an implementation for remaining ImageLoadingView
methods:
extension MKAnnotationView: ImageLoadingView {
public func nk_imageTask(task: ImageTask, didFinishWithResponse response: ImageResponse, options: ImageViewLoadingOptions) {
// Handle task completion
}
}
When you display a collection of images it becomes quite tedious to manage tasks associated with image cells. Nuke takes care of all the complexity for you:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellReuseID, forIndexPath: indexPath)
let imageView: ImageView = <#view#>
imageView.image = nil
imageView.nk_setImageWith(imageURL)
return cell
}
Nuke defines a simple ImageProcessing
protocol that represents image filters. It takes just a couple line of code to create your own filters. You can also compose multiple filters together using ImageProcessorComposition
class.
let filter1: ImageProcessing = <#filter#>
let filter2: ImageProcessing = <#filter#>
var request = ImageRequest(URL: <#image_url#>)
request.processor = ImageProcessorComposition(processors: [filter1, filter2])
Nuke.taskWith(request) {
// Filters are applied, processed image is stored into memory cache
let image = $0.image
}.resume()
ImageProcessing
protocol consists of two methods: one to process the image and one to compare two (heterogeneous) filters. Here's an example of custom image filter that uses Core Image. For more info see Core Image Integration Guide.
public class ImageFilterGaussianBlur: ImageProcessing {
public let radius: Int
public init(radius: Int = 8) {
self.radius = radius
}
public func process(image: UIImage) -> UIImage? {
// The `applyFilter` function is not shipped with Nuke.
return image.applyFilter(CIFilter(name: "CIGaussianBlur", withInputParameters: ["inputRadius" : self.radius]))
}
}
// We need to compare filters to identify cached images
public func ==(lhs: ImageFilterGaussianBlur, rhs: ImageFilterGaussianBlur) -> Bool {
return lhs.radius == rhs.radius
}
Preheating is an effective way to improve user experience in applications that display collections of images. Preheating means loading and caching images that might soon appear on the display. Nuke provides a set of self-explanatory methods for image preheating which are inspired by PHImageManager:
let requests = [ImageRequest(URL: imageURL1), ImageRequest(URL: imageURL2)]
Nuke.startPreheatingImages(requests: requests)
Nuke.stopPreheatingImages(requests: requests)
Nuke can be used in conjuction with Preheat package which automates precaching of content in UICollectionView
and UITableView
. For more info see Image Preheating Guide, Nuke's demo project, and Preheat documentation.
let preheater = PreheatControllerForCollectionView(collectionView: <#collectionView#>)
preheater.delegate = self // Signals when preheat index paths change
Nuke provides both on-disk and in-memory caching.
For on-disk caching it relies on NSURLCache
. The NSURLCache
is used to cache original image data downloaded from the server. This class a part of the URL Loading System's cache management, which relies on HTTP cache.
As an alternative to NSURLCache
Nuke
provides an ImageDiskCaching
protocol that allows you to easily integrate any third-party caching library.
For on-memory caching Nuke provides ImageMemoryCaching
protocol and its implementation in ImageMemoryCache
class built on top of NSCache
. The ImageMemoryCache
is used for fast access to processed images that are ready for display.
The combination of two cache layers results in a high performance caching system. For more info see Image Caching Guide which provides a comprehensive look at HTTP cache, URL Loading System and NSCache.
Nuke automatically leverages both its cache layers. It accesses in-memory cache each time you start an ImageTask
and calls a completion closure synchronously if the image is found.
If you need to access memory cache directly you can use ImageManager
:
let manager = ImageManager.shared
let request = ImageRequest(URL: NSURL(string: "")!)
let response = ImageCachedResponse(image: UIImage(), userInfo: nil)
manager.storeResponse(response, forRequest: request)
let cachedResponse = manager.cachedResponseForRequest(request)
Nuke.taskWith(_:)
family of functions are just shortcuts for methods of the ImageManager
class.
One of the great things about Nuke is that it is a pipeline that loads images using injectable dependencies. These protocols are used to customize that pipeline:
Protocol | Description |
---|---|
ImageDataLoading |
Performs loading of image data (NSData ) |
ImageDecoding |
Decodes NSData to UIImage objects |
ImageMemoryCaching |
Stores processed images into memory cache |
ImageDiskCaching |
Stores data into disk cache |
You can either provide your own implementation of these protocols or customize existing classes that implement them. After you have all the dependencies in place you can create an `ImageManager`:
let dataLoader: ImageDataLoading = <#dataLoader#>
let decoder: ImageDecoding = <#decoder#>
let cache: ImageMemoryCaching = <#cache#>
let configuration = ImageManagerConfiguration(dataLoader: dataLoader, decoder: decoder, cache: cache)
ImageManager.shared = ImageManager(configuration: configuration)
If even those protocols are not enough, you can take a look at the ImageLoading
protocol. It provides a high level API for loading images. This protocol is implemented by the ImageLoader
class that defines a common flow of loading images (load data
-> decode
-> process
) and uses the corresponding ImageDataLoading
, ImageDiskCaching
, ImageDecoding
and ImageProcessing
protocols.
let loader: ImageLoading = <#loader#>
let cache: ImageMemoryCaching = <#cache#>
// The ImageManagerConfiguration(dataLoader:decoder:cache:) constructor is actually
// just a convenience initializer that creates an instance of ImageLoader class
let configuration = ImageManagerConfiguration(loader: loader, cache: cache)
ImageManager.shared = ImageManager(configuration: configuration)
Protocol | Description |
---|---|
ImageManager |
A top-level API for managing images |
ImageDataLoading |
Performs loading of image data (NSData ) |
ImageDecoding |
Converts NSData to UIImage objects |
ImageProcessing |
Processes decoded images |
ImageMemoryCaching |
Stores processed images into memory cache |
ImageDiskCaching |
Stores data into disk cache |
To install Nuke add a dependency to your Podfile:
# source 'https://github.com/CocoaPods/Specs.git'
# use_frameworks!
# platform :ios, "8.0" / :watchos, "2.0" / :osx, "10.9" / :tvos, "9.0"
pod "Nuke"
pod "Nuke-Alamofire-Plugin" # optional
pod "Nuke-AnimatedImage-Plugin" # optional
To install Nuke add a dependency to your Cartfile:
github "kean/Nuke"
github "kean/Nuke-Alamofire-Plugin" # optional
github "kean/Nuke-AnimatedImage-Plugin" # optional
Import installed modules in your source files
import Nuke
import NukeAlamofirePlugin
import NukeAnimatedImagePlugin
- Preheat - Automates preheating (precaching) of content in UITableView and UICollectionView
- Nuke Alamofire Plugin - Alamofire plugin for Nuke that allows you to use Alamofire for networking
- Nuke AnimatedImage Plugin - FLAnimatedImage plugin for Nuke that allows you to load and display animated GIFs
Nuke is available under the MIT license. See the LICENSE file for more info.