Swiftpack.co - Package - kean/Nuke

Powerful Image Loading System

Upgrading from the previous version? Use a Migration Guide.

Nuke provides a simple and efficient way to download and display images in your app. Behind its clear and concise API is an advanced architecture which enables its unique features and offers virtually unlimited possibilities for customization. The primary Nuke feature is performance.

Fast LRU memory and disk cache · SwiftUI · Smart background decompression · Image processing · Elegant builder API · Resumable downloads · Intelligent deduplication · Request prioritization · Low data mode · Prefetching · Rate limiting · Progressive JPEG, HEIF, WebP, SVG, GIF · Alamofire · Combine · Reactive extensions


Getting Started

Nuke is easy to learn and use. Here is an overview of its APIs and features:

To learn more see a full API Reference, and check out the demo project included in the repo. When you are ready to install, follow the Installation Guide. See Requirements for a list of supported platforms. If you encounter any issues, please refer to FAQ or Troubleshooting Guide.

To learn more about the pipeline and the supported formats, see the dedicated guides.

If you'd like to contribute to Nuke see Contributing.


Image View Extensions

Download and display an image in an image view with a single line of code:

Nuke.loadImage(with: url, into: imageView)

Nuke will check if the image exists in the memory cache, and if it does, will instantly display it. If not, the image data will be loaded, decoded, processed, and decompressed in the background.

See Image Pipeline Guide to learn how images are downloaded and processed.

In a Table View

When you request a new image for the existing view, Nuke will prepare it for reuse and cancel any outstanding requests for the view.

func tableView(_ tableView: UITableView, cellForItemAt indexPath: IndexPaths) -> UITableViewCell {
    /* Create a cell ... */
    Nuke.loadImage(with: url, into: cell.imageView)
}

When the view is deallocated, an associated request gets canceled automatically. To manually cancel the request, call Nuke.cancelRequest(for: imageView).

Placeholders, Transitions, Content Modes, Tint Colors

Use ImageLoadingOptions to set a placeholder, select one of the built-in transitions, or provide a custom one.

let options = ImageLoadingOptions(
    placeholder: UIImage(named: "placeholder"),
    transition: .fadeIn(duration: 0.33)
)
Nuke.loadImage(with: url, options: options, into: imageView)

You can even customize content modes or tint colors per image type:

let options = ImageLoadingOptions(
    placeholder: UIImage(named: "placeholder"),
    failureImage: UIImage(named: "failureImage"),
    contentModes: .init(success: .scaleAspectFill, failure: .center, placeholder: .center),
    tintColors: .init(success: .green, failure: .red, placeholder: .yellow)
)

In case you want all image views to have the same behavior, you can modify ImageLoadingOptions.shared.

Please keep in mind that the built-in extensions for image views are designed to get you up and running as quickly as possible. If you want to have more control, or use some of the advanced features, like animated images, it is recommended to use ImagePipeline directly in your custom views.

ImageRequest

ImageRequest allows you to set image processors, change the request priority and more:

let request = ImageRequest(
    url: URL(string: "http://..."),
    processors: [ImageProcessors.Resize(size: imageView.bounds.size)],
    priority: .high
)

Another way to apply processors is by setting the default processors on ImagePipeline.Configuration. These processors will be applied to all images loaded by the pipeline. If the request has a non-empty array of processors, they are going to be applied instead.

The advanced options available via ImageRequestOptions. For example, you can provide a filteredURL to be used as a key for caching in case the URL contains transient query parameters.

let request = ImageRequest(
    url: URL(string: "http://example.com/image.jpeg?token=123")!,
    options: ImageRequestOptions(
        filteredURL: "http://example.com/image.jpeg"
    )
)

There are more options available, to see all of them check the inline documentation for ImageRequestOptions.


Image Processing

Nuke features a powerful and efficient image processing infrastructure with multiple built-in processors which you can find in ImageProcessors namespace, e.g. ImageProcessors.Resize.

This and other screenshots are from the demo project included in the repo.

Resize

To resize an image, use ImageProcessors.Resize:

ImageRequest(url: url, processors: [
    ImageProcessors.Resize(size: imageView.bounds.size)
])

By default, the target size is in points. When the image is loaded, Nuke will downscale it to fill the target area maintaining the aspect ratio. To crop the image set crop to true. For more options, see ImageProcessors.Resize documentation.

Use an optional Builder package for a more concise API.

pipeline.image(with: URL(string: "https://")!)
    .resize(width: 320)
    .blur(radius: 10)

Circle

Rounds the corners of an image into a circle with an optional border.

ImageRequest(url: url, processors: [
    ImageProcessors.Circle()
])

RoundedCorners

Rounds the corners of an image to the specified radius. Make sure you resize the image to exactly match the size of the view in which it gets displayed so that the border appears correctly.

ImageRequest(url: url, processors: [
    ImageProcessors.Circle(radius: 16)
])

GaussianBlur

ImageProcessors.GaussianBlur blurs the input image using one of the Core Image filters.

CoreImageFilter

Apply any of the vast number Core Image filters using ImageProcessors.CoreImageFilter:

ImageProcessors.CoreImageFilter(name: "CISepiaTone")

Custom Processors

For simple one-off operations, use ImageProcessors.Anonymous to create a processor with a closure.

Custom processors need to implement ImageProcessing protocol. For the basic image processing needs, implement process(_:) method and create an identifier which uniquely identifies the processor. For processors with no input parameters, you can return a static string.

public protocol ImageProcessing {
    func process(image: UIImage) -> UIImage? // NSImage on macOS
    var identifier: String // get
}

If your processor needs to manipulate image metadata (ImageContainer), or get access to more information via ImageProcessingContext, there is an additional method that you can implement in addition to process(_:).

public protocol ImageProcessing {
    func process(_ image container: ImageContainer, context: ImageProcessingContext) -> ImageContainer?
}

In addition to var identfier: String, you can implement var hashableIdentifier: AnyHashable to be used by the memory cache where string manipulations would be too slow. By default, this method returns the identifier string. A common approach is to make your processor Hashable and return self from hashableIdentifier.


Image Pipeline

At the core of Nuke is the ImagePipeline class. Use the pipeline directly to load images without displaying them:

let task = ImagePipeline.shared.loadImage(
    with: url,
    progress: { _, completed, total in
        print("progress updated")
    },
    completion: { result: Result<ImageResponse, ImagePipeline.Error> in
        print("task completed")
    }
)

loadImage returns always calls a completion closure asynchronously. To check if the image is stored in a memory cache, use pipeline.cachedImage(for: url).

To download the data without doing any expensive decoding or processing, use loadData(with:progress:completion:).

ImageTask

When you start the request, the pipeline returns an ImageTask object, which can be used for cancellation and more.

task.cancel()
task.priority = .high

Customize Image Pipeline

If you want to build a system that fits your specific needs, you won't be disappointed. There are a lot of things to tweak. You can set custom data loaders and caches, configure image encoders and decoders, change the number of concurrent operations for each individual stage, disable and enable features like deduplication and rate limiting, and more.

To learn more see the inline documentation for ImagePipeline.Configuration and Image Pipeline Guide.

Here are the protocols which can be used for customization:

  • DataLoading – Download (or return cached) image data
  • DataCaching – Store image data on disk
  • ImageDecoding – Convert data into images (see _ImageDecoding for new experimental decoding features)
  • ImageEncoding - Convert images into data
  • ImageProcessing – Apply image transformations
  • ImageCaching – Store images into a memory cache

The entire configuration is described by the ImagePipeline.Configuration struct. To create a pipeline with a custom configuration either call the ImagePipeline(configuration:) initializer or use the convenience one:

let pipeline = ImagePipeline {
    $0.dataLoader = ...
    $0.dataLoadingQueue = ...
    $0.imageCache = ...
    ...
}

And then set the new pipeline as default:

ImagePipeline.shared = pipeline

Default Image Pipeline

The default image pipeline is initialized with the following dependencies:

// Shared image cache with a size limit of ~20% of available RAM.
imageCache = ImageCache.shared

// Data loader with a default `URLSessionConfiguration` and a custom `URLCache`
// with memory capacity 0, and disk capacity 150 MB.
dataLoader = DataLoader()

// Custom aggressive disk cache is disabled by default.
dataCache = nil

// By default uses the decoder from the global registry and the default encoder.
makeImageDecoder = ImageDecoderRegistry.shared.decoder(for:)
makeImageEncoder = { _ in ImageEncoders.Default() }

Each operation in the pipeline runs on a dedicated queue:

dataLoadingQueue.maxConcurrentOperationCount = 6
dataCachingQueue.maxConcurrentOperationCount = 2
imageDecodingQueue.maxConcurrentOperationCount = 1
imageEncodingQueue.maxConcurrentOperationCount = 1
imageProcessingQueue.maxConcurrentOperationCount = 2
imageDecompressingQueue.maxConcurrentOperationCount = 2

There is a list of pipeline settings which you can tweak:

// Automatically decompress images in the background by default.
isDecompressionEnabled = true

// Configure what content to store in the custom disk cache.
dataCacheOptions.storedItems = [.finalImage] // [.originalImageData]

// Avoid doing any duplicated work when loading or processing images.
isDeduplicationEnabled = true

// Rate limit the requests to prevent trashing of the subsystems.
isRateLimiterEnabled = true

// Progressive decoding is an opt-in feature because it is resource intensive.
isProgressiveDecodingEnabled = false

// Don't store progressive previews in memory cache.
isStoringPreviewsInMemoryCache = false

// If the data task is terminated (either because of a failure or a
// cancellation) and the image was partially loaded, the next load will
// resume where it was left off.
isResumableDataEnabled = true

And also a few global options shared between all pipelines:

// Enable to start using `os_signpost` to monitor the pipeline
// performance using Instruments.
ImagePipeline.Configuration.isSignpostLoggingEnabled = false

Caching

LRU Memory Cache

Nuke's default ImagePipeline has two cache layers.

First, there is a memory cache for storing processed images which are ready for display.

// Configure cache
ImageCache.shared.costLimit = 1024 * 1024 * 100 // 100 MB
ImageCache.shared.countLimit = 100
ImageCache.shared.ttl = 120 // Invalidate image after 120 sec

// Read and write images
let request = ImageRequest(url: url)
ImageCache.shared[request] = ImageContainer(image: image)
let image = ImageCache.shared[request]

// Clear cache
ImageCache.shared.removeAll()

ImageCache uses the LRU algorithm – least recently used entries are removed first during the sweep.

HTTP Disk Cache

Unprocessed image data is stored with URLCache.

// Configure cache
DataLoader.sharedUrlCache.diskCapacity = 100
DataLoader.sharedUrlCache.memoryCapacity = 0

// Read and write responses
let request = ImageRequest(url: url)
let _ = DataLoader.sharedUrlCache.cachedResponse(for: request.urlRequest)
DataLoader.sharedUrlCache.removeCachedResponse(for: request.urlRequest)

// Clear cache
DataLoader.sharedUrlCache.removeAllCachedResponses()

Aggressive LRU Disk Cache

If HTTP caching is not your cup of tea, you can try using a custom LRU disk cache for fast and reliable aggressive data caching (ignores HTTP cache control). You can enable it using the pipeline configuration.

ImagePipeline {
    $0.dataCache = try? DataCache(name: "com.myapp.datacache")

    // Also consider disabling the native HTTP cache, see `DataLoader`.
}

By default, the pipeline stores only the original image data. To store downloaded and processed images instead, set dataCacheOptions.storedItems to [.finalImage]. This option is useful if you want to store processed, e.g. downsampled images, or if you want to transcode images to a more efficient format, like HEIF.

To save disk space see ImageEncoders.ImageIO and ImageEncoder.isHEIFPreferred option for HEIF support.


Advanced Features

Image Preheating

Prefetching images in advance can dramatically improve your app's user experience.

// Make sure to keep a strong reference to preheater.
let preheater = ImagePreheater()

preheater.startPreheating(with: urls)

// Cancels all of the preheating tasks created for the given requests.
preheater.stopPreheating(with: urls)

To learn more about other performance optimizations you can do, see Performance Guide.

Keep in mind that prefetching takes up users' data and puts extra pressure on CPU and memory. To reduce the CPU and memory usage, you have an option to choose only the disk cache as a prefetching destination:

// The preheater with `.diskCache` destination will skip image data decoding
// entirely to reduce CPU and memory usage. It will still load the image data
// and store it in disk caches to be used later.
let preheater = ImagePreheater(destination: .diskCache)

On iOS, you can use prefetching APIs in combination with ImagePreheater to automate the process.

Progressive Decoding

To enable progressive image decoding set isProgressiveDecodingEnabled configuration option to true.

Progressive JPEG
let pipeline = ImagePipeline {
    $0.isProgressiveDecodingEnabled = true
    
    // If `true`, the pipeline will store all of the progressively generated previews
    // in the memory cache. All of the previews have `isPreview` flag set to `true`.
    $0.isStoringPreviewsInMemoryCache = true
}

And that's it, the pipeline will automatically do the right thing and deliver the progressive scans via progress closure as they arrive:

let imageView = UIImageView()
let task = ImagePipeline.shared.loadImage(
    with: url,
    progress: { response, _, _ in
        if let response = response {
            imageView.image = response.image
        }
    },
    completion: { result in
        // Display the final image
    }
)

Extensions

There is a variety of extensions available for Nuke:

|Name|Description| |--|--| |FetchImage|SwiftUI integration| |ImagePublisher|Combine publishers for Nuke| |ImageTaskBuilder|A fun and convenient way to use Nuke| |Alamofire Plugin|Replace networking layer with Alamofire and combine the power of both frameworks| |RxNuke|RxSwift extensions for Nuke with examples of common use cases solved by Rx| |WebP Plugin| [Community] WebP support, built by Ryo Kosuge| |Gifu Plugin|Use Gifu to load and display animated GIFs| |FLAnimatedImage Plugin|Use FLAnimatedImage to load and display animated GIFs| |Xamarin NuGet| [Community] Makes it possible to use Nuke from Xamarin|


FetchImage

FetchImage is a Swift package that makes it easy to download images using Nuke and display them in SwiftUI apps. For more info, see the introductory post.

Note: This is an API preview, it might change in the future.

public struct ImageView: View {
    @ObservedObject var image: FetchImage

    public var body: some View {
        ZStack {
            Rectangle().fill(Color.gray)
            image.view?
                .resizable()
                .aspectRatio(contentMode: .fill)
        }
    }
}

Low Data Mode

FetchImage also offers built-in support for low-data mode via a special initializer:

FetchImage(regularUrl: highQualityUrl, lowDataUrl: lowQualityUrl)

Builder

Find the default API a bit boring? Try ImageTaskBuilder, a fun and convenient way to use Nuke.

ImagePipeline.shared.image(with: URL(string: "https://")!)
    .fill(width: 320)
    .blur(radius: 10)
    .priority(.high)
    .start { result in
        print(result)
    }

// Returns `ImageTask` when started.
let imageView: UIImageView

ImagePipeline.shared.image(with: URL(string: "https://")!)
    .fill(width: imageView.size.width)
    .display(in: imageView)

RxNuke

RxNuke adds RxSwift extensions for Nuke and enables common use cases: Going from low to high resolution | Loading the first available image | Showing stale image while validating it | Load multiple images, display all at once | Auto retry on failures | And more

To get a taste of what you can do with this extension, take a look at how easy it is to load the low resolution image first and then switch to high resolution:

let pipeline = ImagePipeline.shared
Observable.concat(pipeline.loadImage(with: lowResUrl).orEmpty,
                  pipeline.loadImage(with: highResUrl).orEmpty)
    .subscribe(onNext: { imageView.image = $0 })
    .disposed(by: disposeBag)

Combine

ImagePublisher adds Combine publishers for Nuke and, just like RxNuke, enables a variety of powerful use cases.


Contribution

Nuke's roadmap is managed in Trello and is publicly available. If you'd like to contribute, please feel free to create a PR.

Minimum Requirements

| Nuke | Swift | Xcode | Platforms | |---------------|-----------------|-----------------|---------------------------------------------------| | Nuke 9.0 | Swift 5.1 | Xcode 11.0 | iOS 11.0 / watchOS 4.0 / macOS 10.13 / tvOS 11.0 | | Nuke 8.0 | Swift 5.0 | Xcode 10.2 | iOS 10.0 / watchOS 3.0 / macOS 10.12 / tvOS 10.0 |

See Installation Guide for information about the older versions.

License

Nuke is available under the MIT license. See the LICENSE file for more info.

Github

link
Stars: 5252

Dependencies

Releases

Nuke 9.1.1 - 2020-06-19 13:58:36

Fixes

  • Fix how RateLimiter clamps the delay – #374 by Tangent
  • Fix an issue where ImageTask would stay in memory indefinitely in certain situations - #377 by Ken Bongort
  • Fix an issue in a demo project where "Rate Limiter" demo would use incorrect cell size on first draw

Nuke 9.1 - 2020-06-01 18:51:27

Enhancements

  • ImageCache now uses DispatchSourceMemoryPressure instead UIApplication.didReceiveMemoryWarningNotification to improve watchOS support - #370, by Dennis Oberhoff
  • Add tintColor option to ImageLoadingOptions - #371 by Basem Emara
  • Minor documentation fixes and improvements

Nuke 9.0 - 2020-05-20 12:45:21

Nuke 9 is the best release so far with refinements across the entire framework and some exciting new additions.

SwiftUI · Combine · Task builder API · New advanced set of core protocols for power-users · HEIF · Transcoding images in disk cache · Progressive decoding performance improvements · Improved resizing APIs · Automatic registering of decoders · SVG · And More

Most of the Nuke APIs are source compatible with Nuke 8. There is also a Nuke 9 Migration Guide to help with migration.

Overview

The primary focus of this release was to build on top the infrastructure introduced in Nuke 8 to deliver more advanced features while keeping the easy things easy. To achieve this, in Nuke 9, all core protocols, like ImageProcessing, ImageEncoding, ImageDecoding, now have a basic subset of methods that you must implement, and then there are new advanced methods which are optional and give you full control over the pipeline.

Along with Nuke 9, three new amazing Swift packages were introduced:

  • FetchImage which makes it easy to use Nuke with SwiftUI
  • ImagePublisher with Combine publishers for Nuke
  • And finally ImageTaskBuilder which introduces a new fun and convenient way to use Nuke. I really love this package. Just look at these APIs:
ImagePipeline.shared.image(with: URL(string: "https://")!)
    .resize(width: 320)
    .blur(radius: 10)
    .priority(.high)
    .load { result in
        print(result)
    }

I would also like to highlight a few other changes to improve documentation.

First, there is a completely new API Reference available generated using SwiftDoc, a new package for generating documentation for Swift projects.

There is a completely new README and two new guides:

  • Image Pipeline Guide with a detailed description of how the pipeline delivers images
  • Image Formats Guide with an overview of the improved decoding/encoding infrastructure and information how to support variety of image formats: GIF, HEIF, SVG, WeP, and more.

There is also a new Troubleshooting Guide.

Another small but delightful change the demo project which can now be run by simply clicking on the project and running it, all thanks to Swift Package Manager magic.

Changelog

General Improvements

  • Bump minimum platform version requirements. The minimum iOS version is now iOS 11 which is a 64-bit only system. This is great news if you are installing your dependencies using Carthage as Nuke is now going to compile twice as fast: no need to compile for i386 and armv7 anymore.

Documentation Improvements

ImageProcessing improvements

There are now two levels of image processing APIs. For the basic processing needs, implement the following method:

func process(_ image: UIImage) -> UIImage? // NSImage on macOS

If your processor needs to manipulate image metadata (ImageContainer), or get access to more information via the context (ImageProcessingContext), there is now an additional method that allows you to do that:

func process(_ container: ImageContainer, context: ImageProcessingContext) -> ImageContainer?
  • All image processors are now available ImageProcessors namespace so it is now easier to find the ones you are looking for. Unrelated types were moved to ImageProcessingOption.
  • Add ImageResponse to ImageProcessingContext
  • New convenience ImageProcessors.Resize.init(width:) and ImageProcessors.Resize.init(height:) initializers

ImageDecoding Improvements

  • Add a new way to register the decoders in ImageDecoderRegistry with ImageDecoderRegistering protocol. public func register<Decoder: ImageDecoderRegistering>(_ decoder: Decoder.Type) - #354
/// An image decoder which supports automatically registering in the decoder register.
public protocol ImageDecoderRegistering: ImageDecoding {
    init?(data: Data, context: ImageDecodingContext)
    // Optional
    init?(partiallyDownloadedData data: Data, context: ImageDecodingContext)
}
  • The default decoder now implements ImageDecoderRegistering protocol
  • Update the way decoders are created. Now if the decoder registry can't create a decoder for the partially downloaded data, the pipeline will no longer create (failing) decoding operation reducing the pressure on the decoding queue
  • Rework ImageDecoding protocol
  • Nuke now supports decompression and processing of images that require image data to work
  • Deprecate ImageResponse.scanNumber, the scan number is now passed in ImageContainer.userInfo[ImageDecodert.scanNumberKey] (this is a format-specific feature and that's why I made it non-type safe and somewhat hidden). Previously, it was also only working for the default ImageDecoders.Default. Now any decoder can pass scan number, or any other information using ImageContainer.userInfo
  • All decoders are now defined in ImageDecoders namespace
  • Add ImageDecoders.Empty
  • Add ImageType struct

ImageEncoding Improvements

#353 - There are now two levels of image encoding APIs. For the basic encoding needs, implement the following method:

func encode(_ image: UIImage) -> UIImage? // NSImage on macOS

If your encoders needs to manipulate image metadata (ImageContainer), or get access to more information via the context (ImageEncodingContext), there is now an additional method that allows you to do that:

func encode(_ container: ImageContainer, context: ImageEncodingContext) -> Data?
  • All image encoders are now available ImageEncoders namespace so it is now easier to find the ones you are looking for.
  • Add ImageEncoders.ImageIO with HEIF support - #344
  • The default adaptive encoder now uses ImageEncoders.ImageIO under the hood and can be configured to support HEIF

Progressive Decoding Improvements

  • You can now opt-in to store progressively generated previews in the memory cache by setting the pipeline option isStoringPreviewsInMemoryCache to true. All of the previews have isPreview flag set to true. - $352

Improved Cache For Processed Images - #345

Nuke 9 revisits data cache for processed images feature introduced in Nuke 8.0 and fixes all the rough edges around it.

There are two primary changes.

1. Deprecate isDataCachingForOriginalImageDataEnabled and isDataCachingForProcessedImagesEnabled properties.

These properties were replaced with a new DataCacheOptions.

public struct DataCacheOptions {
    /// Specifies which content to store in the `dataCache`. By default, the
    /// pipeline only stores the original image data downloaded using `dataLoader`.
    /// It can be configured to encode and store processed images instead.
    ///
    /// - note: If you are creating multiple versions of the same image using
    /// different processors, it might be worse enabling both `.originalData`
    /// and `.encodedImages` cache to reuse the same downloaded data.
    ///
    /// - note: It might be worth enabling `.encodedImages` if you want to
    /// transcode downloaded images into a more efficient format, like HEIF.
    public var storedItems: Set<DataCacheItem> = [.originalImageData]
}

public enum DataCacheItem {
    /// Original image data.
    case originalImageData
    /// Final image with all processors applied.
    case finalImage
}

Now we no longer rely on documentation to make sure that you disable data cache for original image data when you decide to cache processed images instead.

2. Rework DataCacheItem.finalImage behavior.

The primary reason for deprecation is a significantly changed behavior of data cache for processed images.

The initial version introduced back in Nuke 8.0 never really made sense. For example, only images for requests with processors were stored, but not the ones without. You can see how this could be a problem, especially if you disable data cache for original image data which was a recommended option.

The new behavior is much simpler. You set configuration.dataCacheOptions.storedItems to [. finalImage], and Nuke encodes and stores all of the downloaded images, regardless of whether they were processed or not.

DataCache Improvements - #350

Nuke 9 realized the original vision for DataCache. The updated staging/flushing mechanism now performs flushes on certain intervals instead of on every write. This makes some of the new DataCache features possible.

  • flush not performs synchronously
  • Add flush(for:) methods which allows to flush changes on disk only for the given key
  • Add public property let queue: DispatchQueue
  • Add public method func url(for key: Key) -> URL?

ImageContainer

This release introduces ImageContainer type. It is integrated throughout the framework instead of PlatformImage.

Reasoning

  • Separate responsibility. ImageResponse - result of the current request with information about the current request, e.g. URLResponse that was received. ImageContainer - the actual downloaded and processed image regardless of the request
  • Stop relying on Objective-C runtime which animatedImageData was using
  • Stop relying on extending Objective-C classes like UIImage
  • Add type-safe way to attach additional information to downloaded images

Changes

  • Update ImageCaching protocol to store ImageContainer instead of ImageResponse. ImageResponse is a result of the individual request, it should not be saved in caches.
public protocol ImageCaching: AnyObject {
    subscript(request: ImageRequest) -> ImageContainer?
}
  • Update ImagePipeline.cachedImage(for:) method to return ImageContainer
  • Deprecate PlatformImage.animatedImageData, please use ImageContainer.data instead
  • Deprecated ImagePipelineConfiguration.isAnimatedImageDataEnabled, the default ImageDecoder now set ImageContainer.data automatically when it recognizes GIF format

Other

  • ImagePreheater now automatically cancels all of the outstanding tasks on deinit - #349
  • ImagePipeline now has func cacheKey(for request: ImageRequest, item: DataCacheItem) -> String method which return a key for disk cache
  • Change the type of ImageRequest.userInfo from Any? to [AnyHashable: Any]
  • Remove DFCache from demo - #347
  • Remove FLAnimatedImage and Carthage usage from demo - #348
  • Migrate to Swift 5.1 - #351
  • Add ImageType.init(data:)
  • Add ImageLoadingOptions.isProgressiveRenderingEnabled
  • Add public ImageContainer.map
  • Add "Rendering Engines" section in image-formats.md
  • ImageDecoder now attaches ImageType to the image
  • ImageProcessingOptions.Border now accepts unit as a parameter

Fixes

  • Fix how ImageProcesors.Resize compares size when different units are used
  • Fix an issue with ImageProcessors.Resize String identifier being equal with different content modes provided
  • Fix TSan warnings - #365, by Luciano Almeida

Nuke 9 (RC2) - 2020-05-08 23:57:30

Nuke 9 (RC1) - 2020-04-30 21:41:11

No major changes compared to Beta 2. See previous release notes for more info.

Nuke 9 (Beta 2) - 2020-04-09 03:37:54

For changes in Nuke 9, see https://github.com/kean/Nuke/releases/tag/9.0.0-beta.1

Changes

  • Add ImageType.init(data:)
  • Add ImageLoadingOptions.isProgressiveRenderingEnabled
  • Add public ImageContainer.map
  • Add "Rendering Engines" section in image-formats.md
  • ImageDecoder now attaches ImageType to the image
  • ImageProcessingOptions.Border now accepts unit as a parameter

Deprecations

  • Soft-deprecate PlatformImage.animatedImageData
  • Soft-deprecate ImagePipelineConfiguration.isAnimatedImageDataEnabled

Fixes

  • Fix how ImageProcesors.Resize compares size when different units are used
  • Fix an issue with ImageProcessors.Resize String identifier being equal with different content modes provided

Nuke 9 (Beta 1) - 2020-04-01 00:07:45

Nuke 9 is the best release so far with refinements across the entire framework.

SwiftUI · Combine · Task builder API · New advanced set of core protocols for power-users · HEIF · Transcoding images in disk cache · Progressive decoding performance improvements · Improved resizing APIs · Automatic registering of decoders · SVG · And More

Most of the Nuke APIs are source compatible with Nuke 8. There is also a Nuke 9 Migration Guide (WIP) to help with migration.

Overview

The primary focus of this release was to build on top the infrastructure introduced in Nuke 8 to deliver more and better advanced features while keeping the easy things easy. To achieve this, in Nuke 9 all core protocols, like ImageProcessing, ImageEncoding, ImageDecoding, now have a basic subset of methods that you must implement, and then there are new advanced methods which give you full control.

Taking cues from Combine, all processors are now available in ImageProcessors namespace, all encoders are now available in ImageEncoders namespace... you get the idea.

Along with Nuke 9, three new amazing Swift packages were introduced:

  • FetchImage which makes it easy to use Nuke with SwiftUI
  • ImagePublisher with Combine publishers for Nuke
  • And finally ImageTaskBuilder which introduces a new fun and convenient way to use Nuke. I really love this package. Just look at these APIs:
ImagePipeline.shared.image(with: URL(string: "https://")!)
    .resize(width: 320)
    .blur(radius: 10)
    .priority(.high)
    .load { result in
        print(result)
    }

I would also like to highlight two other changes.

First, there is a completely new README and two new guides:

  • Image Pipeline Guide with a detailed description of how the pipeline delivers images
  • Image Formats Guide with an overview of the improved decoding/encoding infrastructure and information how to support variety of image formats: GIF, HEIF, SVG, WeP, and more.

There is also a new Troubleshooting Guide. I would really recommend going through the updated documentation.

Another small but delightful change the demo project which can now be run by simply clicking on the project and running it, all thank to Swift Package Manager magic.

Changelog

General Improvements

  • Bump minimum platform version requirements. The minimum iOS version is now iOS 11 which is a 64-bit only system. This is great news if you are installing your dependencies using Carthage as Nuke is now going to compile twice as fast: no need to compile for i386 and armv7 anymore.

Documentation Improvements

  • Rewrite most of the README
  • Add a completely new Image Pipeline Guide](https://github.com/kean/Nuke/blob/9.0.0-beta.1/Documentation/Guides/image-pipeline.md) which describes in detail how the pipeline works.
  • Add a new Image Formats Guide

ImageContainer

This release introduces ImageContainer type. It is integrated throught the framework instead of PlatformImage.

Reasoning

  • Separate responsibility. ImageResponse - result of the current request with information about the current request, e.g. URLResponse that was received. ImageContainer - the actual downloaded and processed image regardless of the request
  • Stop relying on Objective-C runtime which animatedImageData was using
  • Stop relying on extending Objective-C classes like UIImage
  • Add type-safe way to attach additional information to downloaded images

Changes

  • Update ImageCaching protocol to store ImageContainer instead of ImageResponse. ImageResponse is a result of the individual request, it should not be saved in caches.
public protocol ImageCaching: AnyObject {
    subscript(request: ImageRequest) -> ImageContainer?
}
  • Update ImagePipeline.cachedImage(for:) method to return ImageContainer
  • Deprecate PlatformImage.animatedImageData, please use ImageContainer.data instead
  • Deprecated ImagePipelineConfiguration.isAnimatedImageDataEnabled, the default ImageDecoder now set ImageContainer.data automatically when it recognizes GIF format

ImageProcessing improvements

There are now two levels of image processing APIs. For the basic processing needs, implement the following method:

func process(_ image: UIImage) -> UIImage? // NSImage on macOS

If your processor needs to manipulate image metadata (ImageContainer), or get access to more information via the context (ImageProcessingContext), there is now an additional method that allows you to do that:

func process(_ container: ImageContainer, context: ImageProcessingContext) -> ImageContainer?
  • All image processors are now available ImageProcessors namespace so it is now easier to find the ones you are looking for. Unrelated types were moved to ImageProcessingOption.
  • Add ImageResponse to ImageProcessingContext
  • New convenience ImageProcessors.Resize.init(width:) and ImageProcessors.Resize.init(height:) initializers

ImageDecoding Improvements (WIP)

  • Add a new way to register the decoders in ImageDecoderRegistry with ImageDecoderRegistering protocol. public func register<Decoder: ImageDecoderRegistering>(_ decoder: Decoder.Type) - #354
/// An image decoder which supports automatically registering in the decoder register.
public protocol ImageDecoderRegistering: ImageDecoding {
    init?(data: Data, context: ImageDecodingContext)
    // Optional
    init?(partiallyDownloadedData data: Data, context: ImageDecodingContext)
}
  • The default decoder now implementes ImageDecoderRegistering protocol
  • Update the way decoders are created. Now if the decoder registry can't create a decoder for the partially downloaded data, the pipeline will no longer create (failing) decoding operation reducing the pressure on the decoding queue
  • Rework ImageDecoding protocol
  • Nuke now supports decompression and processing of images that require image data to work
  • Deprecate ImageResponse.scanNumber, the scan number is now passed in ImageContainer.userInfo[ImageDecodert.scanNumberKey] (this is a format-specific feature and that's why I made it non-type safe and somewhat hidden). Previusly it was also only working for the default ImageDecoders.Default. Now any decoder can pass scan number, or any other information using ImageContainer.userInfo
  • All decoders are now defined in ImageDecoders namespace
  • Add ImageDecoders.Empty
  • Add ImageType struct

https://github.com/kean/Nuke/pull/344

ImageEncoding Improvements

#353 - There are now two levels of image encoding APIs. For the basic encoding needs, implement the following method:

func encode(_ image: UIImage) -> UIImage? // NSImage on macOS

If your encoders needs to manipulate image metadata (ImageContainer), or get access to more information via the context (ImageEncodingContext), there is now an additional method that allows you to do that:

func encode(_ container: ImageContainer, context: ImageEncodingContext) -> Data?
  • All image encoders are now available ImageEncoders namespace so it is now easier to find the ones you are looking for.
  • Add ImageEncoders.ImageIO with HEIF support - #344
  • The default adaptive encoder now uses ImageEncoders.ImageIO under the hood and can be configured to support HEIF

Progressive Decoding Improvements

  • You can now opt-in to store progressively generated previews in the memory cache by setting the pipeline option isStoringPreviewsInMemoryCache to true. All of the previews have isPreview flag set to true. - $352

Improved Cache For Processed Images - #345

Nuke 9 revisits data cache for processed images feature introduced in Nuke 8.0 and fixes all the rough edges around it.

There are two primary changes.

1. Deprecate isDataCachingForOriginalImageDataEnabled and isDataCachingForProcessedImagesEnabled properties.

These properties were replaced with a new DataCacheOptions.

public struct DataCacheOptions {
    /// Specifies which content to store in the `dataCache`. By default, the
    /// pipeline only stores the original image data downloaded using `dataLoader`.
    /// It can be configured to encode and store processed images instead.
    ///
    /// - note: If you are creating multiple versions of the same image using
    /// different processors, it might be worse enabling both `.originalData`
    /// and `.encodedImages` cache to reuse the same downloaded data.
    ///
    /// - note: It might be worth enabling `.encodedImages` if you want to
    /// transcode downloaded images into a more efficient format, like HEIF.
    public var storedItems: Set<DataCacheItem> = [.originalImageData]
}

public enum DataCacheItem {
    /// Originl image data.
    case originalImageData
    /// Final image with all processors applied.
    case finalImage
}

Now we no longer rely on documentation to make sure that you disable data cache for original image data when you decide to cache processed images instead.

2. Rework DataCacheItem.finalImage behavior.

The primary reason for deprecation is a significantly changed behavior of data cache for processed images.

The initial version introduced back in Nuke 8.0 never really made sense. For example, only images for requests with processors were stored, but not the ones without. You can see how this could be a problem, especially if you disable data cache for original image data which was a recommended option.

The new behavior is much simpler. You set configuration.dataCacheOptions.storedItems to [. finalImage], and Nuke encodes and stores all of the downloaded images, regardless of whether they were processed or not.

DataCache Improvements - #350

Nuke 9 realized the original vision for DataCache. The updated staging/flushing mechanism now performs flushes on certain intervals instead of on every write. This makes some of the new DataCache features possible.

  • flush not performs synchronously
  • Add flush(for:) methods which allows to flush changes on disk only for the given key
  • Add public property let queue: DispatchQueue
  • Add public method func url(for key: Key) -> URL?

Other

  • ImagePreheater now automatically cancels all of the outstanding tasks on deinit - #349
  • ImagePipeline now has func cacheKey(for request: ImageRequest, item: DataCacheItem) -> String method which return a key for disk cache
  • Change the type of ImageRequest.userInfo from Any? to [AnyHashable: Any]
  • Remove DFCache from demo - #347
  • Remove FLAnimatedImage and Carthage usage from demo - #348
  • Migrate to Swift 5.1 - #351

Nuke 8.4.1 - 2020-03-20 01:13:26

  • Podspec now explicitly specifies supported Swift versions - 340, Richard Lee
  • Fix a memory leak when the URLSession wasn't deallocated correctly - 336

Announcements

There are two new Swift packages available in Nuke ecosystem:

  • FetchImage makes it easy to download images using Nuke and display them in SwiftUI apps. One of the notable features of FetchImage is support for iOS 13 Low Data mode.
  • ImagePublisher provides Combine publishers for some of the Nuke APIs.

Both are distributed exclusively via Swift Package Manager. And both are API previews. Please, try them out, and feel free to contact me with any feedback that you have.

Nuke 8.4 - 2019-11-18 13:26:45

  • Fix an issue with RoundedCorners image processor not respecting the Border parameter – 327, Eric Jensen
  • Add an optional border parameter to the Circle processor – 327, Eric Jensen
  • Add ImagePipelineObserving and DataLoaderObserving protocols to allow users to tap into the internal events of the subsystems to enable logging and other features – 322, Abdallah Nehme
  • Deprecate Nuke.Image to avoid name clashes with SwiftUI.Image in the future , add PlatformImage instead – 321
  • Make ImagePipeline more readable – 320
  • Update demo project to use Swift Package Manager instead of CocoaPods – 319

Nuke 8.3.1 - 2019-10-26 16:42:47

  • Add dark mode support to the demo project – #307, Li Yu

Nuke 8.3 - 2019-10-06 10:44:58

  • Add processors option to ImagePipeline.Configuration300, Alessandro Vendruscolo
  • Add queue option to loadImage and loadData methods of ImagePipeline304
  • Add callbackQueue option to ImagePipeline.Configuration304

Nuke 8.2 - 2019-09-21 07:27:48

Nuke 8.1.1 - 2019-09-01 06:12:47

  • Switch to a versioning scheme which is compatible with Swift Package Manager

Nuke 8.1 - 2019-08-25 07:40:36

  • Configure dispatch queues with proper QoS – #291
  • Remove synchronization points in ImageDecoder which is not needed starting from iOS 10 – #277, Michael Nisi)
  • Add Swift Package Manager to Installation Guides
  • Improve Travis CI setup: run tests on multiple Xcode versions, run thread safety tests, run SwiftLint validations, build demo project, validate Swift package – #279, #280, #281, #284, #285

Nuke 8.0.1 - 2019-07-21 12:28:30

  • Remove synchronization in ImageDecoder which is no longer needed – #277

Nuke 8.0 - 2019-07-08 17:12:27

Nuke 8 is the most powerful, performant, and refined release yet. It contains major advancements it some areas and brings some great new features.

Cache processed images on disk · New built-in image processors · ImagePipeline v2 · Up to 30% faster main thread performance · Result type · Improved deduplication · os_signpost integration · Refined ImageRequest API · Smart decompression · Entirely new documentation

Most of the Nuke APIs are source compatible with Nuke 7. There is also a Nuke 8 Migration Guide to help with migration.

Image Processing

#227 Cache Processed Images on Disk

ImagePipeline now supports caching of processed images on disk. To enable this feature set isDataCacheForProcessedDataEnabled to true in the pipeline configuration and provide a dataCache. You can use a built-in DataCache introduced in Nuke 7.3 or write a custom one.

Image cache can significantly improve the user experience in the apps that use heavy image processors like Gaussian Blur.

#243 New Image Processors

Nuke now ships with a bunch of built-in image processors including:

  • ImageProcessor.Resize
  • ImageProcessor.RoundedCorners
  • ImageProcessor.Circle
  • ImageProcessor.GaussianBlur
  • ImageProcessor.CoreImageFilter

There are also ImageProcessor.Anonymous to create one-off processors from closures and ImageProcessor.Composition to combine two or more processors.

#245 Simplified Processing API

Previously Nuke offered multiple different ways to add processors to the request. Now there is only one, which is also better than all of the previous versions:

let request = ImageRequest(
    url: URL(string: "http://..."),
    processors: [
        ImageProcessor.Resize(size: CGSize(width: 44, height: 44), crop: true),
        ImageProcessor.RoundedCorners(radius: 16)
    ]
)

Processors can also be set using a respective mutable processors property.

Notice that AnyImageProcessor is gone! You can simply use ImageProcessing protocol directly in places where previously you had to use a type-erased version.

#229 Smart Decompression

In the previous versions, decompression was part of the processing API and ImageDecompressor was the default processor set for each image request. This was mostly done to simplify implementation but it was confusing for the users.

In the new version, decompression runs automatically and it no longer a "processor". The new decompression is also smarter. It runs only when needed – when we know that image is still in a compressed format and wasn't decompressed by one of the image processors.

Decompression runs on a new separate imageDecompressingQueue. To disable decompression you can set a new isDecompressionEnabled pipeline configuration option to false.

#247 Avoiding Duplicated Work when Applying Processors

The pipeline avoids doing any duplicated work when loading images. Now it also avoids applying the same processors more than once. For example, let's take these two requests:

let url = URL(string: "http://example.com/image")
pipeline.loadImage(with: ImageRequest(url: url, processors: [
    ImageProcessor.Resize(size: CGSize(width: 44, height: 44)),
    ImageProcessor.GaussianBlur(radius: 8)
]))
pipeline.loadImage(with: ImageRequest(url: url, processors: [
    ImageProcessor.Resize(size: CGSize(width: 44, height: 44))
]))

Nuke will load the image data only once, resize the image once and apply the blur also only once. There is no duplicated work done at any stage. If any of the intermediate results are available in the data cache, they will be used.

ImagePipeline v2

Nuke 8 introduced a major new iteration of the ImagePipeline class. The class was introduced in Nuke 7 and it contained a lot of incidental complexity due to addition of progressive decoding and some other new features. In Nuke 8 it was rewritten to fully embrace progressive decoding. The new pipeline is smaller, simpler, easier to maintain, and more reliable.

It is also faster.

+30% Main Thread Performance

The image pipeline spends even less time on the main thread than any of the previous versions. It's up to 30% faster than Nuke 7.

#239 Load Image Data

Add a new ImagePipeline method to fetch original image data:

@discardableResult
public func loadData(with request: ImageRequest,
                     progress: ((_ completed: Int64, _ total: Int64) -> Void)? = nil,
                     completion: @escaping (Result<(data: Data, response: URLResponse?), ImagePipeline.Error>) -> Void) -> ImageTask

This method now powers ImagePreheater with destination .diskCache introduced in Nuke 7.4 (previously it was powered by a hacky internal API).

#245 Improved ImageRequest API

The rarely used options were extracted into the new ImageRequestOptions struct and the request initializer can now be used to customize all of the request parameters.

#255 filteredURL

You can now provide a filteredURL to be used as a key for caching in case the URL contains transient query parameters:

let request = ImageRequest(
    url: URL(string: "http://example.com/image.jpeg?token=123")!,
    options: ImageRequestOptions(
        filteredURL: "http://example.com/image.jpeg"
    )
)

#241 Adopt Result type

Adopt the Result type introduced in Swift 5. So instead of having a separate response and error parameters, the completion closure now has only one parameter - result.

public typealias Completion = (_ result: Result<ImageResponse, ImagePipeline.Error>) -> Void

Performance

Apart from the general performance improvements Nuke now also offers a great way to measure performance and gain visiblity into how the system behaves when loading images.

#250 Integrate os_signpost

Integrate os_signpost logs for measuring performance. To enable the logs set ImagePipeline.Configuration.isSignpostLoggingEnabled (static property) to true before accessing the shared pipeline.

With these logs, you have visibility into the image pipeline. For more information see WWDC 2018: Measuring Performance Using Logging which explains os_signpost in a great detail.

Screenshot 2019-06-01 at 10 46 52

Documentation

All the documentation for Nuke was rewritten from scratch in Nuke 8. It's now more concise, clear, and it even features some fantastic illustrations:

Screenshot 2019-06-11 at 22 31 18

The screenshots come the the reworked demo project. It gained new demos including Image Processing demo and also a way to change ImagePipeline configuration in runtime.

Misc

  • Add a cleaner way to set ImageTask priority using a new priority property – #251
  • [macOS] Implement image cost calculation for ImageCache#236
  • [watchOS] Add WKInterfaceImage support
  • Future-proof Objective-C ImageDisplaying protocol by adding nuke_ prefixes to avoid clashes in Objective-C runtime
  • Add convenience func decode(data: Data) -> Image? method with a default isFinal argument to ImageDecoding protocol – e3ca5e
  • Add convenience func process(image: Image) -> Image? method to ImageProcessing protocol
  • DataCache will now automatically re-create its root directory if it was deleted underneath it
  • Add public flush method to DataCache

Nuke 8.0-rc.1 - 2019-06-12 17:30:00

Nuke 8 is the most powerful, performant, and refined release yet. It contains major advancements it some areas and brings some great new features. One of the highlights of this release is the documentation which was rewritten from the ground up.

Cache processed images on disk · New built-in image processors · ImagePipeline v2 · Up to 30% faster main thread performance · Result type · Improved deduplication · os_signpost integration · Refined ImageRequest API · Smart decompression · Entirely new documentation

Most of the Nuke APIs are source compatible with Nuke 7. There is also a Nuke 8 Migration Guide to help with migration.

Image Processing

#227 Cache Processed Images on Disk

ImagePipeline now supports caching of processed images on disk. To enable this feature set isDataCacheForProcessedDataEnabled to true in the pipeline configuration and provide a dataCache. You can use a built-in DataCache introduced in Nuke 7.3 or write a custom one.

Image cache can significantly improve the user experience in the apps that use heavy image processors like Gaussian Blur.

#243 New Image Processors

Nuke now ships with a bunch of built-in image processors including:

  • ImageProcessor.Resize
  • ImageProcessor.RoundedCorners
  • ImageProcessor.Circle
  • ImageProcessor.GaussianBlur
  • ImageProcessor.CoreImageFilter

There are also ImageProcessor.Anonymous to create one-off processors from closures and ImageProcessor.Composition to combine two or more processors.

#245 Simplified Processing API

Previously Nuke offered multiple different ways to add processors to the request. Now there is only one, which is also better than all of the previous versions:

let request = ImageRequest(
    url: URL(string: "http://..."),
    processors: [
        ImageProcessor.Resize(size: CGSize(width: 44, height: 44), crop: true),
        ImageProcessor.RoundedCorners(radius: 16)
    ]
)

Processors can also be set using a respective mutable processors property.

Notice that AnyImageProcessor is gone! You can simply use ImageProcessing protocol directly in places where previously you had to use a type-erased version.

#229 Smart Decompression

In the previous versions, decompression was part of the processing API and ImageDecompressor was the default processor set for each image request. This was mostly done to simplify implementation but it was confusing for the users.

In the new version, decompression runs automatically and it no longer a "processor". The new decompression is also smarter. It runs only when needed – when we know that image is still in a compressed format and wasn't decompressed by one of the image processors.

Decompression runs on a new separate imageDecompressingQueue. To disable decompression you can set a new isDecompressionEnabled pipeline configuration option to false.

#247 Avoiding Duplicated Work when Applying Processors

The pipeline avoids doing any duplicated work when loading images. Now it also avoids applying the same processors more than once. For example, let's take these two requests:

let url = URL(string: "http://example.com/image")
pipeline.loadImage(with: ImageRequest(url: url, processors: [
    ImageProcessor.Resize(size: CGSize(width: 44, height: 44)),
    ImageProcessor.GaussianBlur(radius: 8)
]))
pipeline.loadImage(with: ImageRequest(url: url, processors: [
    ImageProcessor.Resize(size: CGSize(width: 44, height: 44))
]))

Nuke will load the image data only once, resize the image once and apply the blur also only once. There is no duplicated work done at any stage. If any of the intermediate results are available in the data cache, they will be used.

ImagePipeline v2

Nuke 8 introduced a major new iteration of the ImagePipeline class. The class was introduced in Nuke 7 and it contained a lot of incidental complexity due to addition of progressive decoding and some other new features. In Nuke 8 it was rewritten to fully embrace progressive decoding. The new pipeline is smaller, simpler, easier to maintain, and more reliable.

It is also faster.

+30% Main Thread Performance

The image pipeline spends even less time on the main thread than any of the previous versions. It's up to 30% faster than Nuke 7.

#239 Load Image Data

Add a new ImagePipeline method to fetch original image data:

@discardableResult
public func loadData(with request: ImageRequest,
                     progress: ((_ completed: Int64, _ total: Int64) -> Void)? = nil,
                     completion: @escaping (Result<(data: Data, response: URLResponse?), ImagePipeline.Error>) -> Void) -> ImageTask

This method now powers ImagePreheater with destination .diskCache introduced in Nuke 7.4 (previously it was powered by a hacky internal API).

#245 Improved ImageRequest API

The rarely used options were extracted into the new ImageRequestOptions struct and the request initializer can now be used to customize all of the request parameters.

#255 filteredURL

You can now provide a filteredURL to be used as a key for caching in case the URL contains transient query parameters:

let request = ImageRequest(
    url: URL(string: "http://example.com/image.jpeg?token=123")!,
    options: ImageRequestOptions(
        filteredURL: "http://example.com/image.jpeg"
    )
)

#241 Adopt Result type

Adopt the Result type introduced in Swift 5. So instead of having a separate response and error parameters, the completion closure now has only one parameter - result.

public typealias Completion = (_ result: Result<ImageResponse, ImagePipeline.Error>) -> Void

Performance

Apart from the general performance improvements Nuke now also offers a great way to measure performance and gain visiblity into how the system behaves when loading images.

#250 Integrate os_signpost

Integrate os_signpost logs for measuring performance. To enable the logs set ImagePipeline.Configuration.isSignpostLoggingEnabled (static property) to true before accessing the shared pipeline.

With these logs, you have visibility into the image pipeline. For more information see WWDC 2018: Measuring Performance Using Logging which explains os_signpost in a great detail.

Screenshot 2019-06-01 at 10 46 52

Documentation

All the documentation for Nuke was rewritten from scratch in Nuke 8. It's now more concise, clear, and it even features some fantastic illustrations:

Screenshot 2019-06-11 at 22 31 18

The screenshots come the the reworked demo project. It gained new demos including Image Processing demo and also a way to change ImagePipeline configuration in runtime.

Misc

  • Add a cleaner way to set ImageTask priority using a new priority property – #251
  • [macOS] Implement image cost calculation for ImageCache#236
  • [watchOS] Add WKInterfaceImage support
  • Future-proof Objective-C ImageDisplaying protocol by adding nuke_ prefixes to avoid clashes in Objective-C runtime
  • Add convenience func decode(data: Data) -> Image? method with a default isFinal argument to ImageDecoding protocol – e3ca5e
  • Add convenience func process(image: Image) -> Image? method to ImageProcessing protocol
  • DataCache will now automatically re-create its root directory if it was deleted underneath it
  • Add public flush method to DataCache

Nuke 8.0-beta.4 - 2019-06-07 20:20:24

A small bump to address the feedback from Nuke 8.0-beta.3.

  • Improve debug descriptions for processors, adopt reverse DNS notation for cache keys
  • Revert the changes made in #254 Improve image view extensions. There is going to be no major changes in the primary Nuke.loadImage(:) API in Nuke 8. The extensions are going to be revisited when adding SwiftUI and Combine support.
  • Tune the performance, now we can safely say there is a +25% improvement in some of the common use cases on the main thread.
  • [Documentation] Update some of the documentation
  • [Demo] Add a Settings screen to the demo project to allow change ImagePipeline configuration in runtime

Nuke 8.0-beta.3 - 2019-06-02 20:13:31

#257 Image Processing Improvements

  • Refactor the existing processors
  • Add new ImageProcessor.Crop, previously cropping was an option in ImageProcessor.Resize and there was a known defect when cropping images smaller than the target size which is fixed in the new implementation
  • Make ImageProcessor.Resize and ImageProcessor.Crop available on macOS
  • Add CustomStringConvertible implementations for each image processor
  • Add documentation for image processors

#259 Revert Addition of ImageTaskDelegate

  • ImageTaskDelegate was a new API introduced in Nuke 8.0-beta.1 to improve the pipeline performance. After some extensive profiling it was clear that this change wasn't truly worth the increased complexity and the changes in the established public API, thus this change was reverted.

Nuke 8.0-beta.2 - 2019-06-01 22:00:09

There quite a few important changes in this update. Probably the most important one is the addition of Deprecated.swift file which eases the transition from Nuke 7 to Nuke 8 which are now almost completely source compatible.

Naturally, this beta includes everything from Nuke 8.0-beta.1.

#250 Integrate os_signpost for profiling

Integrate os_signpost logs for measuring performance. To enable the logs set ImagePipeline.Configuration.isSignpostLoggingEnabled (static property) to true before accessing the shared pipeline.

With these logs, you have visibility into the image pipeline. For more information see WWDC 2018: Measuring Performance Using Logging which explains os_signpost in a great detail.

Screenshot 2019-06-01 at 10 46 52

#254 Improve Image Loading Extensions

  • Add imageView.nk.setImage(with:) family of methods as a replacement for Nuke.loadImage(with:into:). The latter wasn't grammatically correct, that's the first. setImage(with:) methods are also more conventional. So now in order to load an image and display it in a view you would simply do this:
imageView.nk.setImage(with: URL(string: "http://example.com/image.jpeg")!)
  • Future-proof Objective-C ImageDisplaying protocol by adding nuke_ prefixes to avoid clashes in Objective-C runtime
  • Add WKInterfaceImage support

Other Changes

  • Enable processing deduplication by default – #252
  • Add filterURL options to ImageRequestOptions to filter unwanted query parameters when generating cache keys - #255
  • Add Deprecated.swift file to ease transition from Nuke 7 to Nuke 8 - #253
  • Implement image cost calculation in ImageCache for macOS – #236
  • Add a cleaner way to set ImageTask priority using a new priority property – #251
  • Add convenience func decode(data: Data) method with a default isFinal argument to ImageDecoding protocol – e3ca5e
  • DataCache will now automatically re-create its root directory if it was deleted underneath it

Nuke 8.0-beta.1 - 2019-05-23 19:12:14

This is the first Nuke 8 beta. There is going to be at least one more beta released in June updated according to your feedback.

Image Processing Improvements

#227 Caching Processed Images

ImagePipeline now supports caching of processed images. To enable this feature set isDataCacheForProcessedDataEnabled to true in the pipeline configuration and provide a dataCache. You can use a built-in DataCache introduced in Nuke 7.3 which supports parallel reads, and instant writes.

Image cache can significantly improve the user experience in the apps that use heavy image processors like Gaussian Blur.

#243 Add Image Processors

Add the following image processors:

  • ImageProcessor.Resize
  • ImageProcessor.RoundedCorners
  • ImageProcessor.Circle
  • ImageProcessor.GaussianBlur
  • ImageProcessor.CoreImageFilter

More processors will be added in the upcoming releases.

#245 Simplified Processing API

Previously there were quite a few different ways to add processors to the request. Now there is only one, which is also better than all of the previous versions:

let request = ImageRequest(
    url: URL(string: "http://..."),
    processors: [
        ImageProcessor.Resize(size: CGSize(width: 44, height: 44), crop: true),
        ImageProcessor.RoundedCorners(radius: 16)
    ]
)

Processors can also be set using a respective mutable processors property.

Notice that AnyImageProcessor is also finally gone. You can just use ImageProcessing protocol directly everywhere.

#229 Smart Decompression

In the previous versions, the decompression was part of the processing API and ImageDecompressor was the default processor set for each image request. This was mostly done to simplify implementation but it was confusing for the users.

In the new solution, decompression runs automatically and no longer conflicts with the other processors that you set on the request.

The new decompression is also smarter. It runs only when needed: either if there are no processors provided in the request or when these processors didn't change the original image in any way (e.g. ImageProcessor.Resize decided not to upscale the image). Decompression also runs after reading the processed image from disk.

Decompression runs on a new separate imageDecompressingQueue. To disable it set isDecompressionEnabled to false.

#247 Avoiding Duplicated Work when Applying Processors (Experimental)

An experimental feature disabled by default. To enabled it, set isProcessingDeduplicationEnabled to true. When enabled, the pipeline will avoid any duplicated work when processing images. For example, let's take the following requests:

let url = URL(string: "http://example.com/image")
pipeline.loadImage(with: ImageRequest(url: url, processors: [
    ImageProcessor.Resize(size: CGSize(width: 44, height: 44)),
    ImageProcessor.GaussianBlur(radius: 8)
]))
pipeline.loadImage(with: ImageRequest(url: url, processors: [
    ImageProcessor.Resize(size: CGSize(width: 44, height: 44))
]))

Nuke will load the image data only once, resize the image once and apply the blur also only once. There is no duplicated work done at any stage. If any of the intermediate results are available in the data cache, they will be used.

ImagePipeline v2

Nuke 8 introduced a major new iteration of the ImagePipeline class. It was completely rewritten to embrace progressive decoding and deduplication introduced in Nuke 7.

The new pipeline is smaller, simpler, easier to maintain, and more reliable than the previous iteration. It is powered by a new internal Task abstraction which is extremely powerful.

Up to 30% Faster Main Thread Performance

With some of the changed introduced in the pipeline, the primary Nuke.loadImage(with:into:) method became even faster than any of the previous versions on the main thread, up to 30% faster.

#237 Add ImageTaskDelegate

Extend ImagePipeline API with a new method:

public func imageTask(with request: ImageRequest, delegate: ImageTaskDelegate) -> ImageTask

This API is meant to be used for advanced features like progressive image decoding. It is also one of the primary reasons why the pipeline is so much faster in Nuke 8.

#239 Load Image Data

Add a new ImagePipeline method to fetch original image data:

@discardableResult
public func loadData(with request: ImageRequest,
                     progress: ((_ completed: Int64, _ total: Int64) -> Void)? = nil,
                     completion: @escaping (Result<(data: Data, response: URLResponse?), ImagePipeline.Error>) -> Void) -> ImageTask

This method now powers ImagePreheater with destination .diskCache introduced in Nuke 7.4 (previously it was powered by a hacky internal API).

#245 Improved ImageRequest API

The rarely used options were extracted into new ImageRequestOptions struct and the processor initializer can now be used to customize all of the request parameters.

#241 Adopt Result type

Adopt the Result type introduced in Swift 5. So instead of having a separate response and error parameters, the completion closure now has only one parameter - result.

public typealias Completion = (_ result: Result<ImageResponse, ImagePipeline.Error>) -> Void

Future Improvements

There are a few improvements planned for Nuke 8 but which are still in the progress including new performance metrics, new ways to customize cache keys, more processors, more API refinements.

The documentation, the demos, and the migrations guides are also be updated later and available with RC.

Nuke 7.6.3 - 2019-05-01 10:44:22

  • Fix #226ImageTask.setPriority(_:) sometimes crashes

Nuke 7.6.2 - 2019-04-24 04:57:18

  • Fix Thread Sanitizer warnings. The issue was related to unfair_lock usage which was introduced as a replacement for OSAtomic functions in Nuke 7.6. In order to fix the issue, unfair_lock was replaced with simple NSLock. The performance hit is pretty insignificant and definitely isn't worth introducing this additional level of complexity.

Nuke 7.6.1 - 2019-04-13 10:29:17

Nuke 7.6 - 2019-04-07 20:57:59

  • Add Swift 5.0 support – Daniel Storm in #217
  • Add SwiftPM 5.0 support - Vadim Shpakovski in #219
  • Remove Swift 4.0 and Swift 4.1 support
  • Remove iOS 9, tvOS 9, watchOS 2.0, macOS 10.10 and macOS 10.11 support
  • Add a single Nuke target which can build the framework for any platform
  • Replace deprecated OSAtomic functions with unfair_lock, there are no performance regressions

Nuke 7.5.2 - 2018-12-26 11:17:29

  • [macOS] Fix Nuke.loadImage image is not displayed when .fadeIn transition is used – #206
  • Add .alwaysTransition flag to ImageLoadingOptions@gabzsa in #201

Nuke 7.5.1 - 2018-11-04 14:37:01

  • Update Swift version in pbxproj to Swift 4.2, #199
  • Update demo to Swift 4.2

Nuke 7.5 - 2018-10-21 11:40:46

Additions

  • #193 Add an option to ImageDecompressor to allow images to upscale, thanks to @drkibitz
  • #197 Add a convenience initializer to ImageRequest which takes an image processor (ImageProcessing) as a parameter, thanks to @drkibitz

Improvements

  • Add a guarantee that if you cancel ImageTask on the main thread, you won't receive any more callbacks (progress, completion)
  • Improve internal Operation performance (async operation subclass), images are loading up to 5% faster

Removals

Nuke 7 had a lot of API changes, to make the migration easier it shipped with Deprecated.swift file (536 line of code) which enabled Nuke 7 to be almost 100% source-compatible with Nuke 6. It's been 6 months since Nuke 7 release, so now it's finally a good time to remove all of this code.

With all these removals, Nuke compiles up to 10% faster. Test coverage is at 93.35%.

Nuke 7.4.2 - 2018-10-01 17:45:41

  • #174 Fix an issue with an ImageView reuse logic where in rare cases a wrong image would be displayed, thanks to @michaelnisi

Nuke 7.4.1 - 2018-09-25 05:33:43

  • Disable automatic stopPreheating which was causing issues