Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isLocalResourcesSupportEnabled #779

Merged
merged 3 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading