- Fix #206: [macOS]
Nuke.loadImage
image is not displayed when.fadeIn
transition is used - #201: add
.alwaysTransition
flag toImageLoadingOptions
, thanks to @gabzsa
- Update Swift version in pbxproj to Swift 4.2, #199
- Update demo to Swift 4.2
- #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
- 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, images are loading up to 5% faster
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.
- #174 Fix an issue with an
ImageView
reuse logic where in rare cases a wrong image would be displayed, thanks to @michaelnisi
- Disable automatic
stopPreheating
which was causing some issues
- Add an
ImagePreheater.Destination
option toImagePreheater
. The default option is.memoryCache
which works exactly the wayImagePreheater
used to work before. The more interesting option is.diskCache
. 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. - Add convenience
func startPreheating(with urls: [URL])
function which creates requests with.low
requests for you. ImagePreheater
now automatically cancels all of the managed outstanding requests on deinit.- Add
UICollectionViewDataSourcePrefetching
demo on iOS 10+. Nuke still supports iOS 9 so Preheat is also still around.
- #187 Fix an issue with progress handler reporting incorrect progress for resumed (206 Partial Content) downloads
- Remove
enableExperimentalAggressiveDiskCaching
function fromImagePipeline.Configuration
, please useDataCache
directly instead - Update Performance Guide
- #178 Fix TSan warning being triggered by performance optimization in
ImageTask.cancel()
(false positive) - Fix an issue where a request (
ImageRequest
) with a default processor and a request with the same processor but set manually would have different cache keys
ImagePipeline
now updates the priority of shared operations when the registered tasks get canceled (was previosuly only reacting to added tasks)- Fix an issue where
didFinishCollectingMetrics
closure wasn't called for the tasks completed with images found in memory cache and the tasks canceled before they got a chance to run. Now every created tasks gets a correspondingdidFinishCollectingMetrics
call.
This release introduces new DataCache
type and features some other improvements in custom data caching.
- Add new
DataCache
type - a cache backed by a local storage with an LRU cleanup policy. This type is a reworked version of the experimental data cache which was added in Nuke 7.0. It's now much simpler and also faster. It allows for reading and writing in parallel, it has a simple consistent API, and I hope it's going to be a please to use.
Migration note: The storage format - which is simply a bunch of files in a directory really - is backward compatible with the previous implementation. If you'd like the new cache to continue working with the same path, please create it with "com.github.kean.Nuke.DataCache" name and use the same filename generator that you were using before:
try? DataCache(name: "com.github.kean.Nuke.DataCache", filenameGenerator: filenameGenerator)
-
#160
DataCache
now has a defaultFilenameGenerator
on Swift 4.2 which usesSHA1
hash function provided byCommonCrypto
(CommonCrypto
is not available on the previous version of Swift). -
#171 Fix a regression introduced in version 7.1. where experimental
DataCache
would not perform LRU data sweeps. -
Update
DataCaching
protocol. To store data you now need to implement a synchronous methodfunc cachedData(for key: String) -> Data?
. This change was necessary to make the data cache fit nicely inImagePipeline
infrastructure where each stage is managed by a separateOperationQueue
and each operation respects the priority of the image requests associated with it. -
Add
dataCachingQueue
parameter toImagePipeline.Configuration
. The defaultmaxConcurrentOperationCount
is2
. -
Improve internal
Operation
type performance.
Nuke's roadmap is now publicly available. Please feel free to contribute!
This update addresses tech debt introduces in version 7.1 and 7.2. All of the changes made in these version which improved deduplication are prerequisites for implementing smart prefetching which be able to skip decoding, load to data cache only, etc.
- Simpler and more efficient model for managing decoding and processing operations (including progressive ones). All operations now take the request priority into account. The processing operations are now created per processor, not per image loading session which leads to better performance.
- When subscribing to existing session which already started processing, pipeline will try to find existing processing operation.
- Update
DFCache
integration demo to use newDataCaching
protocol - Added "Default Image Pipeline" section and "Image Pipeline Overview" sections in README.
- Update "Third Party Libraries" guide to use new
DataCaching
protocol
- #163 Add
DataCaching
protocol which can be used to implement custom data cache. It's not documented yet, the documentation going to be updated in 7.2.1.
- Initial iOS 12.0, Swift 4.2 and Xcode 10 beta 1 support
- #167
ImagePipeline
now usesOperationQueue
instead ofDispatchQueue
for decoding images. The queue now respectsImageRequest
priority. If the task is cancelled the operation added to a queue is also cancelled. The queue can be configured viaImagePipeline.Configuration
. - #167
ImagePipeline
now updates processing operations' priority.
- Fix a regression where in certain deduplication scenarios a wrong image would be saved in memory cache
- Fix MP4 demo project
- Improve test coverage, bring back
DataCache
(internal) tests
- Improve deduplication. Now when creating two requests (at roughly the same time) for the same images but with two different processors, the original image is going to be downloaded once (used to be twice in the previous implementation) and then two separate processors are going to be applied (if the processors are the same, the processing will be performed once).
- Greatly improved test coverage.
- Fix an issue when setting custom
loadKey
for the request, thehashValue
of the default key was still used. - Fix warnings "Decoding failed with error code -1" when progressively decoding images. This was the result of
ImageDecoder
trying to decode incomplete progressive scans. - Fix an issue where
ImageDecoder
could produce a bit more progressive scans than necessary.
- Add a section in README about replacing GIFs with video formats (e.g.
MP4
,WebM
) - Add proof of concept in the demo project that demonstrates loading, caching and displaying short
mp4
videos using Nuke
- #161 Fix the contentModes not set when initializing an ImageLoadingOptions object
Nuke 7 is the biggest release yet. It has a lot of massive new features, new performance improvements, and some API refinements. Check out new Nuke website to see quick videos showcasing some of the new features.
Nuke 7 is almost completely source-compatible with Nuke 6.
Add support for progressive JPEG (built-in) and WebP (build by the Ryo Kosuge). See README for more info. See demo project to see it in action.
Add new ImageProcessing
protocol which now takes an extra ImageProcessingContext
parameter. One of its properties is scanNumber
which allows you to do things like apply blur to progressive image scans reducing blur radius with each new scan ("progressive blur").
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. In many use cases resumable downloads are a massive improvement to user experience, especially on the mobile internet.
Resumable downloads require server support for HTTP Range Requests. Nuke supports both validators (ETag
and Last-Modified
).
The resumable downloads are enabled by default. The resumable data is automatically stored in efficient memory cache. This is a good default, but future versions might add more customization options.
Add a new set of powerful methods to load images into views. Here's one of those methods:
@discardableResult
public func loadImage(with request: ImageRequest,
options: ImageLoadingOptions = ImageLoadingOptions.shared,
into view: ImageDisplayingView,
progress: ImageTask.ProgressHandler? = nil,
completion: ImageTask.Completion? = nil) -> ImageTask?
You can now pass progress
and completion
closures as well as new ImageLoadingOptions
struct which offers a range of options:
public struct ImageLoadingOptions {
public static var shared = ImageLoadingOptions()
public var placeholder: Image?
public var transition: Transition?
public var failureImage: Image?
public var failureImageTransition: Transition?
public var isPrepareForReuseEnabled = true
public var pipeline: ImagePipeline?
public var contentModes: ContentModes?
/// Content modes to be used for each image type (placeholder, success, failure).
public struct ContentModes {
public var success: UIViewContentMode
public var failure: UIViewContentMode
public var placeholder: UIViewContentMode
}
/// An animated image transition.
public struct Transition {
public static func fadeIn(duration: TimeInterval, options: UIViewAnimationOptions = [.allowUserInteraction]) -> Transition
public static func custom(_ closure: @escaping (ImageDisplayingView, Image) -> Void) -> Transition
}
}
ImageView
will now also automatically prepare itself for reuse (can be disabled via ImageLoadingOptions
)
Instead of an ImageTarget
protocol we now have a new simple ImageDisplaying
protocol which relaxes the requirement what can be used as an image view (it's UIView & ImageDisplaying
now). This achieves two things:
- You can now add support for more classes (e.g.
MKAnnotationView
by implementingImageDisplaying
protocol - You can override the
display(image:
method inUIImageView
subclasses (e.g.FLAnimatedImageView
)
The previous Manager
+ Loading
architecture (terrible naming, responsibilities are often confusing) was replaced with a new unified ImagePipeline
class. ImagePipeline
was built from the ground-up to support all of the powerful new features in Nuke 7 (progressive decoding, resumable downloads, performance metrics, etc).
There is also a new ImageTask
class which feels the gap where user or pipeline needed to communicate between each other after the request was started. ImagePipeline
and ImageTask
offer a bunch of new features:
- To cancel the request you now simply need to call
cancel()
on the task (ImageTask
) which is a bit more user-friendly than previousCancellationTokenSource
infrastructure. ImageTask
offers a new way to track progress (in addition to closures) - nativeFoundation.Progress
(created lazily)ImageTask
can be used to dynamically change the priority of the executing tasks (e.g. the user opens a new screen, you lower the priority of outstanding tasks)- In
ImagePipeline.Configuration
you can now provide custom queues (OperationQueue
) for data loading, decoding and processing (separate queue for each stage). - You can set a custom shared
ImagePipeline
.
Add built-in support for animated images (everything expect the actual rendering). To enable rendering you're still going to need a third-party library (see FLAnimatedImage and Gifu plugins). The changes made in Nuke dramatically simplified those plugins making both of them essentially obsolete - they both now have 10-30 lines of code, you can just copy this code into your project.
- Add new
ImageCaching
protocol for memory cache which now works with a newImageRespone
class. You can do much more intelligent things in your cache implementations now (e.g. make decisions on when to evict image based on HTTP headers). - Improve cache write/hit/miss performance by 30% by getting rid of AnyHashable overhead.
ImageRequest
cacheKey
andloadKey
are now optional. If you use them, Nuke is going to use them instead of built-in internalImageRequest.CacheKey
andImageRequest.LoadKey
. - Add
TTL
support inImageCache
Add a completely new custom LRU disk cache which can be used for fast and reliable aggressive data caching (ignores HTTP cache control). The new cache lookups are up to 2x faster than URLCache
lookups. You can enable it using pipeline's configuration:
When enabling disk cache you must provide a keyEncoder
function which takes image request's url as a parameter and produces a key which can be used as a valid filename. The demo project uses sha1 to generate those keys.
$0.enableExperimentalAggressiveDiskCaching(keyEncoder: {
guard let data = $0.cString(using: .utf8) else { return nil }
return _nuke_sha1(data, UInt32(data.count))
})
The public API for disk cache and the API for using custom disk caches is going to be available in the future versions.
Existing API already allows you to use custom disk cache by implementing
DataLoading
protocol, but this is not the most straightforward option.
When optimizing performance, it's important to measure. Nuke collects detailed performance metrics during the execution of each image task:
ImagePipeline.shared.didFinishCollectingMetrics = { task, metrics in
print(metrics)
}
(lldb) po metrics
Task Information {
Task ID - 1
Duration - 22:35:16.123 – 22:35:16.475 (0.352s)
Was Cancelled - false
Is Memory Cache Hit - false
Was Subscribed To Existing Session - false
}
Session Information {
Session ID - 1
Total Duration - 0.351s
Was Cancelled - false
}
Timeline {
22:35:16.124 – 22:35:16.475 (0.351s) - Total
------------------------------------
nil – nil (nil) - Check Disk Cache
22:35:16.131 – 22:35:16.410 (0.278s) - Load Data
22:35:16.410 – 22:35:16.468 (0.057s) - Decode
22:35:16.469 – 22:35:16.474 (0.005s) - Process
}
Resumable Data {
Was Resumed - nil
Resumable Data Count - nil
Server Confirmed Resume - nil
}
ImagePreheater
now checksImageCache
synchronously before creating tasks which makes it slightly more efficient.RateLimiter
now uses the same sync queue as theImagePipeline
reducing a number of dispatched blocks- Smarter
RateLimiter
which no longer attempt to execute pending tasks when the bucket isn't full resulting in idle dispatching of blocks. I've used a CountedSet to see how well it works in practice and it's perfect. Nice small win. - Add
ImageDecoderRegistry
to configure decoders globally. - Add
ImageDecodingContext
to provide as much information as needed to select a decoder. ImageTask.Completion
now containsImageResponse
(image + URLResponse) instead of just plain image.
CancellationToken
,CancellationTokenSource
- continued to be used internally, If you'd like to continue using cancellation tokens please consider copying this code into your project.DataDecoding
,DataDecoder
,DataDecoderComposition
- replaced by a new image decoding infrastructure (ImageDecoding
,ImageDecoder
,ImageDecodingRegistry
etc).Request
renamed toImageRequest
.- Deprecate
Result
type. It was only used in a single completion handler so it didn't really justify its existence. More importantly, I wasn't comfortable providing a publicResult
type as part of the framework.
This is the final pre-release version. The only thing left to do is finish updating the documentation.
Changes in 7.0-rc1:
- Add more
ImageLoadingOptions
includingfailureImage
,contentModes
and custom transitions. ImageView
will now automatically prepare itself for reuse (can be disabled viaImageLoadingOptions
)- Add
ImageDisplaying
protocol and relax the requirement what can be used as an image view (it'sUIView & ImageDisplaying
now). This achieves two things:- You can now add support for more classes (e.g.
MKAnnotationView
by implementingImageDisplaying
protocol - You can override the
display(image:
method inUIImageView
subclasses (e.g.FLAnimatedImageView
).
- You can now add support for more classes (e.g.
- Update new
ImageProcessing
protocol to add additionalImageProcessingContext
parameter. This enabled features like_ProgressiveBlurImageProcessor
which blurs only first few scans of the progressive image with each new scan having reduced blur radius (see Progressive JPEG Demo).
- Add built-in support for animated images (everything except the actual rendering). To enable rendering you're still going to need a plugin (see FLAnimatedImage and Gifu plugins). The changes made in Nuke dramatically simplify those plugins making both of them essentially obsolete (they both now have 10-30 lines of code).
- Simplify
ImagePipeline
closure-based API. RemoveprogressiveImageHandler
, pass partial images into existingprogress
closure. - Improve test coverage of new features.
This is the final beta version. The release version is going to be available next week.
Add a completely new custom LRU disk cache which can be used for fast and reliable aggressive (no validation) data caching. The new cache lookups are up to 2x faster than URLCache
lookups. You can enable it using pipeline's configuration:
$0.enableExperimentalAggressiveDiskCaching(keyEncoder: {
guard let data = $0.cString(using: .utf8) else { return nil }
return _nuke_sha1(data, UInt32(data.count))
})
When enabling disk cache you must provide a keyEncoder
function which takes image request's url as a parameter and produces a key which can be used as a valid filename. The demo project uses sha1 to generate those keys.
The public API for disk cache and the API for using custom disk caches is going to be available the future versions.
Existing API already allows you to use custom disk cache by implementing
DataLoading
protocol, but this is not the most straightforward option.
- New
ImageCaching
protocol for memory cache with methods likefunc storeResponse(_ response: ImageRespone, for request: ImageRequest)
(it use to be justsubscript[key: AnyHashable] -> Image?
. You can do much more intelligent things in your cache implementations now (e.g. make decisions on when to evict image based on HTTP headers). Plus there is more room for optimization (get rid of AnyHashable overhead). - Improve cache write/hit/miss performance by 30% by getting rid of AnyHashable overhead.
ImageRequest
cacheKey
andloadKey
are now optional. If you use them, Nuke is going to use them instead of built-in internalImageRequest.CacheKey
andImageRequest.LoadKey
. - Add
TTL
support inImageCache
Nuke finally has all of the basic convenience options that you would expect from an image loading framework:
Nuke.loadImage(
with: url,
options: ImageLoadingOptions(
placeholder: UIImage(named: "placeholder"),
transition: .crossDissolve(0.33)
),
into: imageView
)
- Performance improvements in performance metrics, they are virtually free now
- Performance improvements in
ImageTask
cancellation. - Add progress to
ImageTask
. Progress object is created lazily (it's creation is relatively expensive) - Deprecate
Result
type. It was only used in a single completion handler so it didn't really justify its existence. More imporantly, in case of image loading you're really just interested in whether the image was loaded or not. The error is there mostly for diagnostics. We also no longer pollute users' project with yet anotherResult
implementation. ImageTask.Completion
now gives youImageResponse
(image + URLResponse) instead of just plain image.- More generic
Cancellable
protocol instead ofDataLoadingTask
You need a pipeline with progressive decoding enabled:
let pipeline = ImagePipeline {
$0.isProgressiveDecodingEnabled = true
}
And that's it, you can start observing images as they are produced by the pipeline:
let imageView = UIImageView()
let task = pipeline.loadImage(with: url) {
imageView.image = $0.value
}
task.progressiveImageHandler = {
imageView.image = $0
}
The progressive decoding only kicks in when Nuke determines that the image data does contain a progressive JPEG. The decoder intelligently scans the data and only produces a new image when it receives a full new scan (progressive JPEGs normally have around 10 scans).
See "Progressive Decoding" demo to see progressive JPEG in practice. You can also uncomment the code that blurs the first few scans of the image which makes them look a bit nicer.
- Mov resumable data implementation to the pipeline which means it will automatically start working with Alamofire plugin and other custom loaders
- Fix an issue with
206 Partial Content
handling - Add a test suite
- Add
ImagePipeline.Configuration.isResumableDataEnabled flag
(enabled by default) - Add support for
ETag
(beta1 only had support forLast-Modified
).
- Extend a number of metrics introduced in Nuke 7.0-beta1
- Nicer debug output:
(lldb) po task.metrics
Task Information {
Task ID - 5
Total Duration - 0.363
Was Cancelled - false
Is Memory Cache Hit - false
Was Subscribed To Existing Image Loading Session - false
}
Timeline {
12:42:06.559 - Start Date
12:42:06.923 - End Date
}
Image Loading Session {
Session Information - {
Session ID - 5
Total Duration - 0.357
Was Cancelled - false
}
Timeline {
12:42:06.566 - Start Date
12:42:06.570 - Data Loading Start Date
12:42:06.904 - Data Loading End Date
12:42:06.909 - Decoding Start Date
12:42:06.912 - Decoding End Date
12:42:06.913 - Processing Start Date
12:42:06.922 - Processing End Date
12:42:06.923 - End Date
}
Resumable Data {
Was Resumed - nil
Resumable Data Count - nil
Server Confirmed Resume - nil
}
}
Nuke.loadImage(with:into:)
now returns a task (discardable)- Add
ImageDecoderRegistry
to configure decoders globally - Add
ImageDecodingContext
to provide as much information as needed to select a decoder
- Smarter
RateLimiter
which no longer attempt to execute pending tasks when the bucket isn't full resulting in idle dispatching of blocks. I've used a CountedSet to see how well it works in practice and it's perfect. Nice small win. RateLimiter
now uses the same sync queue as theImagePipeline
reducing a number of dispatched blocks
DataDecoding
,DataDecoder
,DataDecoderComposition
- replaced by a new image decoding infrastructure (ImageDecoding
,ImageDecoder
,ImageDecodingRegistry
etc)CancellationToken
,CancellationTokenSource
- continued to be used internally, if you want to use those types in your own project consider copying themtypealias ProgerssHandler
is not nested inImageTask
(ImageTask.ProgressHandler
)
Nuke 7 is the next major milestone continuing the trend started in Nuke 6 which makes the framework more pragmatic and mature. Nuke 7 is more ergonomic, fast, and more powerful.
Nuke 7.0-beta1
is an early released (compared to 6.0-beta1
). There are still some major changes coming in next betas. To make migration easier Nuke 7 is almost fully source compatible with Nuke 6, but many APIs were deprecated and will be removed soon.
There are four major new features in Nuke 7:
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. The resumable downloads are enabled by default.
By default resumable data is stored in an efficient memory cache. Future versions might include more customization.
In many use, cases reusable downloads are a massive improvement. Next betas will feature more customization options for resumable downloads (e.g. customizable resumable data storage).
The previous Manager
+ Loading
architecture (terrible naming, responsibilities are often confused) was replaced with a new unified ImagePipeline
class. There is also a new ImageTask
class which feels the gap where user or pipeline needed to communicate with each other after the request was started.
ImagePipeline
and ImageTask
have a bunch of new features:
- In
ImagePipeline.Configuration
you can now provider custom queues (OperationQueue
) for data loading, decoding and processing (each stage). This way you have more access to queuing (e.g. you can changequalityOfService
, suspend queues) etc and you can also use the same queue across different pipelines. - There are two APIs: convenience ones with blocks (
loadImage(with:completion:)
) and new oneimageTask(with:)
which returns newImageTask
class which gives you access to more advanced features. To start a task callresume()
method, to cancel the task callcancel()
. - Dynamically change priority of executing tasks.
- Set a custom shared
ImagePipeline
.
This feature is still in development and might be coming in one of the next beta.
Nuke captures detailed metrics on each image task:
(lldb) p task.metrics
(Nuke.ImageTaskMetrics) $R2 = {
taskId = 9
timeCreated = 545513853.67615998
timeResumed = 545513853.67778301
timeCompleted = 545513860.90999401
session = 0x00007b1c00011100 {
sessionId = 9
timeDataLoadingStarted = 545513853.67789805
timeDataLoadingFinished = 545513853.74310505
timeDecodingFinished = 545513860.90150297
timeProcessingFinished = 545513860.90990996
urlResponse = 0x00007b0800066960 {
ObjectiveC.NSObject = {}
}
downloadedDataCount = 35049
}
wasSubscibedToExistingTask = false
isMemoryCacheHit = false
wasCancelled = false
}
- Improve main-thread performance by another 20%.
ImagePreheater
now checksImageCache
synchronously before creating tasks which makes it more efficient.
- Users were confused by separate set of
loadImage(with:into:handler:)
methods so they were removed. There were adding very little convenience for a lot of mental overhead. It's fairly easy to reimplement them the way you want
- Prefix all classes with Image starting with a new ImagePipeline. This makes code more readable. It felt awkward to use types like ‘Request’ in your project. ‘Request’ is an integral part of ‘Nuke’, but you are only using it in your project once or twice.
- Lower macOS deployment target to 10.10. #156.
- Improve README: add detailed Image Pipeline section, Performance section, rewrite Usage guide
- Add
Request.Priority
with 5 available options ranging from.veryLow
to.veryHigh
. One of the use cases ofRequest.Priority
is to lower the priority of preheating requests. In case requests get deduplicated the task's priority is set to the highest priority of registered requests and gets updated when requests are added or removed from the task.
- Fix warnings on Xcode 9.3 beta 3
Loader
implementation changed a bit, it is less clever now and is able to accommodate new features like request priorities- Minor changes in style guide to make codebase more readable
- Switch to native
NSLock
, there doesn't seem to be any performance wins anymore when usingpthread_mutex
directly
- #146 fix disk cache path for macOS, thanks to @willdahlberg
About 8 months ago I finally started using Nuke in production. The project has matured from a playground for experimenting with Swift features to something that I rely on in my day's job.
There are three main areas of improvements in Nuke 6:
- Performance. Nuke 6 is fast! The primary
loadImage(with:into:)
method is now 1.5x faster thanks to performance improvements ofCancellationToken
,Manager
,Request
andCache
types. And it's not just main thread performance, many of the background operations were also optimized. - API refinements. Some common operations that were surprisingly hard to do are not super easy. And there are no more implementation details leaking into a public API (e.g. classes like
Deduplicator
). - Fixes some inconveniences like Thread Sanitizer warnings (false positives!). Improved compile time. Better documentation.
- Implements progress reporting kean#81
- Scaling images is now super easy with new convenience
Request
initialisers (Request.init(url:targetSize:contentMode:
andRequest.init(urlRequest:targetSize:contentMode:
) - Add a way to add anonymous image processors to the request (
Request.process(key:closure:)
andRequest.processed(key:closure:)
) - Add
Loader.Options
which can be used to configureLoader
(e.g. change maximum number of concurrent requests, disable deduplication or rate limiter, etc).
- Improve performance of
CancellationTokenSource
,Loader
,TaskQueue
- Improve
Manager
performance by reusing contexts objects between requests - Improve
Cache
by ~30% for most operations (hits, misses, writes) Request
now stores all of the parameters in the underlying reference typed container (it used to store just reference typed ones). TheRequest
struct now only has a single property with a reference to an underlying container.- Parallelize image processing for up to 2x performance boost in certain scenarios. Might increase memory usage. The default maximum number of concurrent tasks is 2 and can be configured using
Loader.Options
. Loader
now always call completion on the main thread.- Move
URLResponse
validation fromDataDecoder
toDataLoader
- Make use of some Swift 4 feature like nested types inside generic types.
- Improve compile time.
- Wrap
Loader
processing and decoding tasks intoautoreleasepool
which reduced memory footprint.
- Get rid of Thread Sanitizer warnings in
CancellationTokenSource
(false positive) - Replace
Foundation.OperationQueue
& customFoundation.Operation
subclass with a newQueue
type. It's simpler, faster, and gets rid of pesky Thread Sanitizer warnings kean#141
- Remove global
loadImage(...)
functions kean#142 - Remove static
Request.loadKey(for:)
andRequest.cacheKey(for:)
functions. The keys are now simply returned inRequest
'sloadKey
andcacheKey
properties which are also no longer optional now. - Remove
Deduplicator
class, make this functionality part ofLoader
. This has a number of benefits: reduced API surface, improves performance by reducing the number of queue switching, enables new features like progress reporting. - Remove
Scheduler
,AsyncScheduler
,Loader.Schedulers
,DispatchQueueScheduler
,OperationQueueScheduler
. This whole infrastructure was way too excessive. - Make
RateLimiter
private. DataLoader
now works withURLRequest
, notRequest
- Fix memory leak in
Loader
- regression introduced in6.0-beta1
- Get rid of Thread Sanitizer warnings in
CancellationTokenSource
(false positive) - Improve performance of
CancellationTokenSource
- Improve
Cache
hits and writes performance by ~15% - Improve
Loader
performance
About 8 months ago I've started using Nuke in production. The project matured from being a playground for experimenting with Swift features to something that I rely on in my days work. The primary goal behind Nuke 6 is to simplify the project even further, and to get rid of the implementation details leaking into a public API.
Nuke is now Swift 4 only. It's simpler, smaller (< 1000 lines of code) , and faster. It features progress reporting and makes it simpler to create custom data loader (e.g. Alamofire data loader).
- Implements progress reporting kean#81
- Remove global
loadImage(...)
functions kean#142 - Remove
Deduplicator
class, make this functionality part ofLoader
. This has a number of benefits: reduced API surface, improves performance by reducing number of queue switching, enables new features like progress reporting. - Remove
Scheduler
,AsyncScheduler
,Loader.Schedulers
,DispatchQueueScheduler
,OperationQueueScheduler
. This whole infrastructure was way too excessive. - Make
RateLimiter
private.
- Replace
Foundation.OperationQueue
& customFoundation.Operation
subclass with a newQueue
type. It's simpler, faster, and gets rid of pesky Thread Sanitizer warnings kean#141 DataLoader
now works withURLRequest
, notRequest
Loader
now always call completion on the main thread.- Move
URLResponse
validation fromDataDecoder
toDataLoader
- Make use of some Swift 4 feature like nested types inside generic types.
Add support for both Swift 3.2 and 4.0.
- Fix Swift 4 warnings
- Add
DataDecoder.sharedUrlCache
to easy access for sharedURLCache
object - Add references to RxNuke
- Minor improvements under the hood
- De facto
Manager
has already implementedLoading
protocol in Nuke 5 (you could use it to load images directly w/o targets). Now it also conforms toLoading
protocols which gives access to some convenience functions available inLoading
extensions. - Add
static func targetSize(for view: UIView) -> CGSize
method toDecompressor
- Simpler, faster
Preheater
- Improved documentation
- #116
Manager
can now be used to load images w/o specifying a target Preheater
is now initialized withManager
instead of object conforming toLoading
protocol
Nuke 5 is a relatively small release which removes some of the complexity from the framework.
One of the major changes is the removal of promisified API as well as Promise
itself. Promises were briefly added in Nuke 4 as an effort to simplify async code. The major downsides of promises are compelex memory management, extra complexity for users unfamiliar with promises, complicated debugging, performance penalties. Ultimately I decided that promises were adding more problems that they were solving.
- Remove promisified API, use simple closures instead. For example,
Loading
protocol's methodfunc loadImage(with request: Request, token: CancellationToken?) -> Promise<Image>
was replaced with a method with a completion closurefunc loadImage(with request: Request, token: CancellationToken?, completion: @escaping (Result<Image>) -> Void)
. The same applies toDataLoading
protocol. - Remove
Promise
class - Remove
PromiseResolution<T>
enum - Remove
Response
typealias - Add
Result<T>
enum which is now used as a replacement forPromiseResolution<T>
(for instance, inTarget
protocol, etc)
- Remove memory cache from
Loader
Manager
now not only reads, but also writes toCache
Manager
now has new methods to load images w/o target (Nuke 5.0.1)
The reason behind this change is to reduce confusion about Cache
usage. In previous versions the user had to pass Cache
instance to both Loader
(which was both reading and writing to cache asynchronously), and to Manager
(which was just reading from the cache synchronously). In a new setup it's clear who's responsible for managing memory cache.
Those two types were included in Nuke to make integrating third party caching libraries a bit easier. However, they were actually not that useful. Instead of using those types you could've just wrapped DataLoader
yourself with a comparable amount of code and get much more control. For more info see Third Party Libraries: Using Other Caching Libraries.
Loader
constructor now provides a default value forDataDecoding
objectDataLoading
protocol now works with aNuke.Request
and notURLRequest
in case some extra info fromURLRequest
is required- Reduce default
URLCache
disk capacity from 200 MB to 150 MB - Reduce default
maxConcurrentOperationCount
ofDataLoader
from 8 to 6 - Shared objects (like
Manager.shared
) are now constants. Preheater
is now initialized withManager
instead ofLoading
object- Add new Third Party Libraries guide.
- Improved documentation
Bunch of improvements in built-in Promise
:
Promise
now also uses newLock
- faster creation, faster locking- Add convenience
isPending
,resolution
,value
anderror
properties - Simpler implementation migrated from Pill.Promise*
*Nuke.Promise
is a simplified variant of Pill.Promise (doesn't allow throws
, adds completion
, etc). The Promise
is built into Nuke to avoid fetching external dependencies.
- Fix deadlock in
Cache
- small typo, much embarrassment 😄 (kean/Nuke-Alamofire-Plugin#8)
Nuke 4.1 is all about performance. Here are some notable performance improvements:
loadImage(with:into:)
method with a default config is 6.3x fasterCache
operations (write/hit/miss) are from 3.1x to 4.5x faster
Nuke 4.0 focused on stability first, naturally there were some performance regressions. With the version 4.1 Nuke is again the fastest framework out there. The performance is ensured by a new set of performance tests.
If you're interested in the types of optimizations that were made check out recent commits. There is a lot of awesome stuff there!
Nuke 4.1 also includes a new Performance Guide and a collection of Tips and Tricks.
- Add convenience method
loadImage(with url: URL, into target: AnyObject, handler: @escaping Handler)
(more useful than anticipated). - #88 Add convenience
cancelRequest(for:)
function - Use
@discardableResult
inPromise
where it makes sense - Simplified
Loader
implementation Cache
nodes are no longer deallocated recursively onremoveAll()
anddeinit
(I was hitting stack limit in benchmarks, it's impossible in real-world use).- Fix: All
Cache
publictrim()
methods are now thread-safe too.
Nuke 4 has fully adopted the new Swift 3 changes and conventions, including the new API Design Guidelines.
Nuke 3 was already a slim framework. Nuke 4 takes it a step further by simplifying almost all of its components.
Here's a few design principles adopted in Nuke 4:
- Protocol-Oriented Programming. Nuke 3 promised a lot of customization by providing a set of protocols for loading, caching, transforming images, etc. However, those protocols were vaguely defined and hard to implement in practice. Protocols in Nuke 4 are simple and precise, often consisting of a single method.
- Single Responsibility Principle. For example, instead of implementing preheating and deduplicating of equivalent requests in a single vague
ImageManager
class, those features were moved to separate classes (Preheater
,Deduplicator
). This makes core classes much easier to reason about. - Principle of Least Astonishment. Nuke 3 had a several excessive protocols, classes and methods which are all gone now (
ImageTask
,ImageManagerConfiguration
just to name a few). Those features are much easier to use now. - Simpler Async. Image loading involves a lot of asynchronous code, managing it was a chore. Nuke 4 adopts two design patterns (Promise and CancellationToken) that solve most of those problems.
The adoption of those design principles resulted in a simpler, more testable, and more concise code base (which is now under 900 slocs, compared to AlamofireImage's 1426, and Kingfisher's whopping 2357).
I hope that Nuke 4 is going to be a pleasure to use. Thanks for your interest 😄
You can learn more about Nuke 4 in an in-depth Nuke 4 Migration Guide.
Nuke 4 features a new custom LRU memory cache which replaced NSCache
. The primary reason behind this change was the fact that NSCache
is not LRU. The new Nuke.Cache
has some other benefits like better performance, and more control which would enable some new advanced features in future versions.
There is a known problem with URLSession
that it gets trashed pretty easily when you resume and cancel URLSessionTasks
at a very high rate (say, scrolling a large collection view with images). Some frameworks combat this problem by simply never cancelling URLSessionTasks
which are already in .running
state. This is not an ideal solution, because it forces users to wait for cancelled requests for images which might never appear on the display.
Nuke has a better, classic solution for this problem - it introduces a new RateLimiter
class which limits the rate at which URLSessionTasks
are created. RateLimiter
uses a token bucket algorithm. The implementation supports quick bursts of requests which can be executed without any delays when "the bucket is full". This is important to prevent the rate limiter from affecting "normal" requests flow. RateLimiter
is enabled by default.
You can see RateLimiter
in action in a new Rate Limiter Demo
added in the sample project.
Make sure to check out new Toucan plugin which provides a simple API for processing images. It supports resizing, cropping, rounded rect masking and more.
- Swift 2.3 support
- Preheating is now thread-safe #75
- #71 ImageViewLoadingController now cancels tasks synchronously, thanks to @adomanico
- Demo project update to support CocoaPods 1.0
- #69 Bitcode support for Carthage builds, thanks to @vincentsaluzzo
- #64 Fix a performance regression: images are now decoded once per DataTask like they used to
- #65 Fix an issue custom on-disk cache (
ImageDiskCaching
) was calledsetData(_:response:forTask:)
method when the error wasn't nil - Add notifications for NSURLSessionTask state changes to enable activity indicators (based on kean/Nuke-Alamofire-Plugin#4)
- Update for Swift 2.2
- Move
ImagePreheatController
to a standalone package Preheat - Remove deprecated
suspend
method fromImageTask
- Remove
ImageFilterGaussianBlur
and Core Image helper functions which are now part of Core Image Integration Guide - Cleanup project structure (as expected by SPM)
Manager
constructor now has a default value for configurationnk_setImageWith(URL:)
method no longer resizes images by default, because resizing is not effective in most cases- Remove
nk_setImageWith(request:options:placeholder:)
method, it's trivial ImageLoadingView
default implementation no longer implements "Cross Dissolve" animations, useImageViewLoadingOptions
instead (seeanimations
orhandler
property)- Remove
ImageViewDefaultAnimationDuration
, useImageViewLoadingOptions
instead (seeanimations
property) ImageDisplayingView
protocol now has a singlenk_displayImage(_)
method instead of ank_image
property- Remove
nk_targetSize
property fromUI(NS)View
extension
- #60 Add custom on-disk caching support (see
ImageDiskCaching
protocol) - Reduce dynamic dispatch
ImageTask
suspend
method is deprecated, implementation does nothingImageLoader
now limits a number of concurrentNSURLSessionTasks
- Add
maxConcurrentSessionTaskCount
property toImageLoaderConfiguration
- Add
taskReusingEnabled
property toImageLoaderConfiguration
- Add Swift Package Manager support
- Update documentation
- #57
ImageDecompressor
now usesCGImageAlphaInfo.NoneSkipLast
for opaque images - Add
ImageProcessorWithClosure
that can be used for creating anonymous image filters ImageLoader
ensures thread safety of image initializers by running decoders on aNSOperationQueue
withmaxConcurrentOperationCount=1
. However,ImageDecoder
class is now also made thread safe.
- #53 ImageRequest no longer uses NSURLSessionTaskPriorityDefault, which requires CFNetwork that doesn't get added as a dependency automatically
Nuke now has an official website!
- #48 Update according to Swift API Design Guidelines. All APIs now just feel right.
- Add
UIImage
extension with helper functions forCore Image
:nk_filter(_:)
, etc. - Add
ImageFilterGaussianBlur
as an example of a filter on top ofCore Image
framework - Add
ImageRequestMemoryCachePolicy
enum that specifies the wayManager
interacts with a memory cache;NSURLRequestCachePolicy
no longer affects memory cache - #17 Add
priority
toImageRequest
- Add
removeResponseForKey()
method toImageMemoryCaching
protocol and the corresponding method toManager
- Implement congestion control for
ImageLoader
that preventsNSURLSession
trashing - Simplify
ImageLoaderDelegate
by combining methods that were customizing processing in a single high-level method:imageLoader(_:processorFor:image:)
. Users now have more control over processing - Add
NSURLResponse?
parameter todecode
method fromImageDecoding
protocol DataLoading
protocol no longer hasisLoadEquivalentRequest(_:toRequest)
andisCacheEquivalentRequest(_:toRequest)
. Those methods are now part ofImageLoaderDelegate
and they have default implementationImageResponseInfo
is now a struct- Improved error reporting (codes are now stored in enum, more codes were added, error is now created with a failure reason)
- Move
nk_ImageTask(_:didFinishWithResponse:options)
method toImageLoadingView
protocol, that's really where it belongs to - Add
handler
property toImageViewLoadingOptions
that allows you to completely override display/animate logic inImageLoadingView
- Remove
nk_prepareForReuse
method fromImageLoadingView
extensions (useless) - Remove
placeholder
fromImageViewLoadingOptions
, move it to a separate argument which is only available onImageDisplayingView
s - Add
animated
,userInfo
toImageViewLoadingOptions
ImageViewLoadingOptions
is now nonull everywhere- Add
setImageWith(task:options:)
method toImageViewLoadingController
- If you add a completion handler for completed task, the response is now marked as
isFastResponse = true
- Fix an issue that allowed incomplete image downloads to finish successfully when using built-in networking
equivalentProcessors(rhs:lhs:)
function is now private (and it also is renamed)- Remove public
isLoadEquivalentToRequest(_:)
andisCacheEquivalentToRequest(_:)
methods fromImageRequest
extension - Add
ImageTaskProgress
struct that represents load progress, movefractionCompleted
property fromImageTask
toImageTaskProgress
- Remove public helper function
allowsCaching
fromImageRequest
extension - Remove deprecated
XCPSetExecutionShouldContinueIndefinitely
from playground
- #46 Add option to disable memory cache storage, thanks to @RuiAAPeres
- Add Core Image Integration Guide
- Fill most of the blanks in the documentation
- #47 Fix target size rounding errors in image downscaling (Pyry Jahkola @pyrtsa)
- Add
imageScale
property toImageDecoder
class that returns scale to be used when creatingUIImage
(iOS, tvOS, watchOS only) - Wrap each iteration in
ProcessorComposition
in anautoreleasepool
- #20 Add preheating for UITableView (see ImagePreheatControllerForTableView class)
- #41 Enhanced tvOS support thanks to @joergbirkhold
- #39 UIImageView: ImageLoadingView extension no available on tvOS
- Add factory method for creating session tasks in DataLoader
- Improved documentation
- #35 ImageDecompressor now uses
32 bpp, 8 bpc, CGImageAlphaInfo.PremultipliedLast
pixel format which adds support for images in an obscure formats, including 16 bpc images. - Improve docs
- #25 Add tvOS support
- #33 Add app extensions support for OSX target (other targets were already supported)
- #30 Add new protocols and extensions to make it easy to add full featured image loading capabilities to custom UI components. Here's how it works:
extension MKAnnotationView: ImageDisplayingView, ImageLoadingView {
// That's it, you get default implementation of all the methods in ImageLoadingView protocol
public var nk_image: UIImage? {
get { return self.image }
set { self.image = newValue }
}
}
- #30 Add UIImageView extension instead of custom UIImageView subclass
- Back to the Mac! All new protocol and extensions for UI components (#30) are also available on a Mac, including new NSImageView extension.
- #26 Add
getImageTaskWithCompletion(_:)
method to Manager - Add essential documentation
- Add handy extensions to ImageResponse