Nuke v9.0.0-beta.1 Release Notes

Release Date: 2020-04-01 // almost 4 years ago
  • 🚀 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 inprint(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

    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) // Optionalinit?(partiallyDownloadedData data: Data, context: ImageDecodingContext) }

    • 0️⃣ 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

    #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