Skip to content

Commit

Permalink
Merge pull request #779 from kean/local-resources-support
Browse files Browse the repository at this point in the history
Add isLocalResourcesSupportEnabled
  • Loading branch information
kean authored Apr 24, 2024
2 parents 4275c68 + 800e86d commit d4758c8
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Fix https://github.com/kean/Nuke/issues/763 SwiftUI Warning: Accessing StateObject's object without being installed on a View when using `onStart`
- Fix https://github.com/kean/Nuke/issues/758 by adding support for initializing `ImageProcessors.CoreImageFilter` with `CIFilter` instances
- Add support for disk cache lookup for intermediate processed images (as opposed to only final and original as before)
- Add an optimization that loads local resources with `file` and `data` schemes quickly without using `DataLoader` and `URLSession`. If you rely on the existing behavior, this optimization can be turned off using the `isLocalResourcesSupportEnabled` configuration option. https://github.com/kean/Nuke/pull/779
- Deprecate `ImagePipeline.Configuration.dataCachingQueue` and perform data cache lookups on the pipeline's queue, reducing the amount of context switching
- Update the infrastructure for coalescing image-processing tasks to use the task-dependency used for other operations

Expand Down
4 changes: 4 additions & 0 deletions Sources/Nuke/Pipeline/ImagePipelineConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ extension ImagePipeline {
/// `Last-Modified`). Resumable downloads are enabled by default.
public var isResumableDataEnabled = true

/// If enabled, the pipeline will load the local resources (`file` and
/// `data` schemes) inline without using the data loader. By default, `true`.
public var isLocalResourcesSupportEnabled = true

/// A queue on which all callbacks, like `progress` and `completion`
/// callbacks are called. `.main` by default.
public var callbackQueue = DispatchQueue.main
Expand Down
12 changes: 11 additions & 1 deletion Sources/Nuke/Tasks/TaskFetchOriginalData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,22 @@ final class TaskFetchOriginalData: ImagePipelineTask<(Data, URLResponse?)> {
private var data = Data()

override func start() {
guard let urlRequest = request.urlRequest else {
guard let urlRequest = request.urlRequest, let url = urlRequest.url else {
// A malformed URL prevented a URL request from being initiated.
send(error: .dataLoadingFailed(error: URLError(.badURL)))
return
}

if url.isLocalResource && pipeline.configuration.isLocalResourcesSupportEnabled {
do {
let data = try Data(contentsOf: url)
send(value: (data, nil), isCompleted: true)
} catch {
send(error: .dataLoadingFailed(error: error))
}
return
}

if let rateLimiter = pipeline.rateLimiter {
// Rate limiter is synchronized on pipeline's queue. Delayed work is
// executed asynchronously also on the same queue.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -624,17 +624,17 @@ class ImagePipelineDataCachePolicyTests: XCTestCase {
XCTAssertEqual(dataCache.store.count, 2)
}

// MARK: Local Storage
// MARK: Local Resources

func testImagesFromLocalStorageNotCached() {
// GIVEN
pipeline = pipeline.reconfigured {
$0.dataCachePolicy = .automatic
}

// GIVEN request without a processor
let request = ImageRequest(url: URL(string: "file://example/image.jpeg"))
let request = ImageRequest(url: Test.url(forResource: "fixture", extension: "jpeg"))

// WHEN
expect(pipeline).toLoadImage(with: request)
wait()
Expand All @@ -652,8 +652,8 @@ class ImagePipelineDataCachePolicyTests: XCTestCase {
}

// GIVEN request with a processor
let request = ImageRequest(url: URL(string: "file://example/image.jpeg") ,processors: [.resize(width: 100)])
let request = ImageRequest(url: Test.url(forResource: "fixture", extension: "jpeg") ,processors: [.resize(width: 100)])

// WHEN
expect(pipeline).toLoadImage(with: request)
wait()
Expand All @@ -671,8 +671,8 @@ class ImagePipelineDataCachePolicyTests: XCTestCase {
}

// GIVEN request without a processor
let request = ImageRequest(url: URL(string: "data://example/image.jpeg"))
let request = ImageRequest(url: Test.url(forResource: "fixture", extension: "jpeg"))

// WHEN
expect(pipeline).toLoadImage(with: request)
wait()
Expand All @@ -682,7 +682,28 @@ class ImagePipelineDataCachePolicyTests: XCTestCase {
XCTAssertEqual(dataCache.writeCount, 0)
XCTAssertEqual(dataCache.store.count, 0)
}


func testImagesFromData() {
// GIVEN
pipeline = pipeline.reconfigured {
$0.dataCachePolicy = .automatic
}

// GIVEN request without a processor
let data = Test.data(name: "fixture", extension: "jpeg")
let url = URL(string: "data:image/jpeg;base64,\(data.base64EncodedString())")
let request = ImageRequest(url: url)

// WHEN
expect(pipeline).toLoadImage(with: request)
wait()

// THEN original image data is stored in disk cache
XCTAssertEqual(encoder.encodeCount, 0)
XCTAssertEqual(dataCache.writeCount, 0)
XCTAssertEqual(dataCache.store.count, 0)
}

// MARK: Misc

func testSetCustomImageEncoder() {
Expand Down

0 comments on commit d4758c8

Please sign in to comment.