From 8e1309698f080809b3418b20934888621dd0109e Mon Sep 17 00:00:00 2001 From: Amol Prabhu Date: Wed, 7 Aug 2024 22:35:26 -0400 Subject: [PATCH 1/4] Fix ImagePipelineDelgate not being weak --- .../Nuke/Pipeline/ImagePipeline+Cache.swift | 14 ++++++------ Sources/Nuke/Pipeline/ImagePipeline.swift | 16 +++++++------- .../Nuke/Tasks/TaskFetchOriginalData.swift | 10 ++++----- .../Nuke/Tasks/TaskFetchOriginalImage.swift | 2 +- Sources/Nuke/Tasks/TaskLoadImage.swift | 22 +++++++++++-------- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift b/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift index 5637d3550..112170514 100644 --- a/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift +++ b/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift @@ -189,7 +189,7 @@ extension ImagePipeline.Cache { /// Returns image cache (memory cache) key for the given request. public func makeImageCacheKey(for request: ImageRequest) -> ImageCacheKey { - if let customKey = pipeline.delegate.cacheKey(for: request, pipeline: pipeline) { + if let customKey = pipeline.delegate?.cacheKey(for: request, pipeline: pipeline) { return ImageCacheKey(key: customKey) } return ImageCacheKey(request: request) // Use the default key @@ -197,7 +197,7 @@ extension ImagePipeline.Cache { /// Returns data cache (disk cache) key for the given request. public func makeDataCacheKey(for request: ImageRequest) -> String { - if let customKey = pipeline.delegate.cacheKey(for: request, pipeline: pipeline) { + if let customKey = pipeline.delegate?.cacheKey(for: request, pipeline: pipeline) { return customKey } return "\(request.preferredImageId)\(request.thumbnail?.identifier ?? "")\(ImageProcessors.Composition(request.processors).identifier)" @@ -223,7 +223,7 @@ extension ImagePipeline.Cache { private func decodeImageData(_ data: Data, for request: ImageRequest) -> ImageContainer? { let context = ImageDecodingContext(request: request, data: data, cacheType: .disk) - guard let decoder = pipeline.delegate.imageDecoder(for: context, pipeline: pipeline) else { + guard let decoder = pipeline.delegate?.imageDecoder(for: context, pipeline: pipeline) else { return nil } return (try? decoder.decode(context))?.container @@ -231,16 +231,16 @@ extension ImagePipeline.Cache { private func encodeImage(_ image: ImageContainer, for request: ImageRequest) -> Data? { let context = ImageEncodingContext(request: request, image: image.image, urlResponse: nil) - let encoder = pipeline.delegate.imageEncoder(for: context, pipeline: pipeline) - return encoder.encode(image, context: context) + let encoder = pipeline.delegate?.imageEncoder(for: context, pipeline: pipeline) + return encoder?.encode(image, context: context) } private func imageCache(for request: ImageRequest) -> (any ImageCaching)? { - pipeline.delegate.imageCache(for: request, pipeline: pipeline) + pipeline.delegate?.imageCache(for: request, pipeline: pipeline) } private func dataCache(for request: ImageRequest) -> (any DataCaching)? { - pipeline.delegate.dataCache(for: request, pipeline: pipeline) + pipeline.delegate?.dataCache(for: request, pipeline: pipeline) } // MARK: Options diff --git a/Sources/Nuke/Pipeline/ImagePipeline.swift b/Sources/Nuke/Pipeline/ImagePipeline.swift index 1b8c88029..1072ab2b2 100644 --- a/Sources/Nuke/Pipeline/ImagePipeline.swift +++ b/Sources/Nuke/Pipeline/ImagePipeline.swift @@ -29,7 +29,7 @@ public final class ImagePipeline: @unchecked Sendable { /// Provides access to the underlying caching subsystems. public var cache: ImagePipeline.Cache { .init(pipeline: self) } - let delegate: any ImagePipelineDelegate + weak var delegate: (any ImagePipelineDelegate)? private var tasks = [ImageTask: TaskSubscription]() @@ -289,7 +289,7 @@ public final class ImagePipeline: @unchecked Sendable { let task = ImageTask(taskId: nextTaskId, request: request, isDataTask: isDataTask, pipeline: self, onEvent: onEvent) // Important to call it before `imageTaskStartCalled` if !isDataTask { - delegate.imageTaskCreated(task, pipeline: self) + delegate?.imageTaskCreated(task, pipeline: self) } task._task = Task { try await withUnsafeThrowingContinuation { continuation in @@ -317,7 +317,7 @@ public final class ImagePipeline: @unchecked Sendable { tasks[task] = worker.subscribe(priority: task.priority.taskPriority, subscriber: task) { [weak task] in task?._process($0) } - delegate.imageTaskDidStart(task, pipeline: self) + delegate?.imageTaskDidStart(task, pipeline: self) onTaskStarted?(task) } @@ -346,16 +346,16 @@ public final class ImagePipeline: @unchecked Sendable { } if !isDataTask { - delegate.imageTask(task, didReceiveEvent: event, pipeline: self) + delegate?.imageTask(task, didReceiveEvent: event, pipeline: self) switch event { case .progress(let progress): - delegate.imageTask(task, didUpdateProgress: progress, pipeline: self) + delegate?.imageTask(task, didUpdateProgress: progress, pipeline: self) case .preview(let response): - delegate.imageTask(task, didReceivePreview: response, pipeline: self) + delegate?.imageTask(task, didReceivePreview: response, pipeline: self) case .cancelled: - delegate.imageTaskDidCancel(task, pipeline: self) + delegate?.imageTaskDidCancel(task, pipeline: self) case .finished(let result): - delegate.imageTask(task, didCompleteWithResult: result, pipeline: self) + delegate?.imageTask(task, didCompleteWithResult: result, pipeline: self) } } } diff --git a/Sources/Nuke/Tasks/TaskFetchOriginalData.swift b/Sources/Nuke/Tasks/TaskFetchOriginalData.swift index 3e21d66df..b1f60f97e 100644 --- a/Sources/Nuke/Tasks/TaskFetchOriginalData.swift +++ b/Sources/Nuke/Tasks/TaskFetchOriginalData.swift @@ -80,8 +80,8 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { signpost(self, "LoadImageData", .begin, "URL: \(urlRequest.url?.absoluteString ?? ""), resumable data: \(Formatter.bytes(resumableData?.data.count ?? 0))") - let dataLoader = pipeline.delegate.dataLoader(for: request, pipeline: pipeline) - let dataTask = dataLoader.loadData(with: urlRequest, didReceiveData: { [weak self] data, response in + let dataLoader = pipeline.delegate?.dataLoader(for: request, pipeline: pipeline) + let dataTask = dataLoader?.loadData(with: urlRequest, didReceiveData: { [weak self] data, response in guard let self else { return } self.pipeline.queue.async { self.dataTask(didReceiveData: data, response: response) @@ -99,7 +99,7 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { guard let self else { return } signpost(self, "LoadImageData", .end, "Cancelled") - dataTask.cancel() + dataTask?.cancel() finish() // Finish the operation! self.tryToSaveResumableData() @@ -170,11 +170,11 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { extension AsyncPipelineTask where Value == (Data, URLResponse?) { func storeDataInCacheIfNeeded(_ data: Data) { let request = makeSanitizedRequest() - guard let dataCache = pipeline.delegate.dataCache(for: request, pipeline: pipeline), shouldStoreDataInDiskCache() else { + guard let dataCache = pipeline.delegate?.dataCache(for: request, pipeline: pipeline), shouldStoreDataInDiskCache() else { return } let key = pipeline.cache.makeDataCacheKey(for: request) - pipeline.delegate.willCache(data: data, image: nil, for: request, pipeline: pipeline) { + pipeline.delegate?.willCache(data: data, image: nil, for: request, pipeline: pipeline) { guard let data = $0 else { return } // Important! Storing directly ignoring `ImageRequest.Options`. dataCache.storeData(data, for: key) diff --git a/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift b/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift index 385a23508..062e91b36 100644 --- a/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift +++ b/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift @@ -62,7 +62,7 @@ final class TaskFetchOriginalImage: AsyncPipelineTask { if let decoder { return decoder } - let decoder = pipeline.delegate.imageDecoder(for: context, pipeline: pipeline) + let decoder = pipeline.delegate?.imageDecoder(for: context, pipeline: pipeline) self.decoder = decoder return decoder } diff --git a/Sources/Nuke/Tasks/TaskLoadImage.swift b/Sources/Nuke/Tasks/TaskLoadImage.swift index b11270537..6d4a38ed4 100644 --- a/Sources/Nuke/Tasks/TaskLoadImage.swift +++ b/Sources/Nuke/Tasks/TaskLoadImage.swift @@ -27,7 +27,7 @@ final class TaskLoadImage: AsyncPipelineTask { private func decodeCachedData(_ data: Data) { let context = ImageDecodingContext(request: request, data: data, cacheType: .disk) - guard let decoder = pipeline.delegate.imageDecoder(for: context, pipeline: pipeline) else { + guard let decoder = pipeline.delegate?.imageDecoder(for: context, pipeline: pipeline) else { return didFinishDecoding(with: nil) } decode(context, decoder: decoder) { [weak self] in @@ -82,7 +82,8 @@ final class TaskLoadImage: AsyncPipelineTask { ImagePipeline.Error.processingFailed(processor: processor, context: context, error: error) } } - self.pipeline.queue.async { + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.operation = nil self.didFinishProcessing(result: result, isCompleted: isCompleted) } @@ -115,9 +116,12 @@ final class TaskLoadImage: AsyncPipelineTask { operation = pipeline.configuration.imageDecompressingQueue.add { [weak self] in guard let self else { return } let response = signpost(isCompleted ? "DecompressImage" : "DecompressProgressiveImage") { - self.pipeline.delegate.decompress(response: response, request: self.request, pipeline: self.pipeline) + self.pipeline.delegate?.decompress(response: response, request: self.request, pipeline: self.pipeline) } - self.pipeline.queue.async { + + guard let response else { return } + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.operation = nil self.didReceiveDecompressedImage(response, isCompleted: isCompleted) } @@ -128,7 +132,7 @@ final class TaskLoadImage: AsyncPipelineTask { ImageDecompression.isDecompressionNeeded(for: response) && !request.options.contains(.skipDecompression) && hasDirectSubscribers && - pipeline.delegate.shouldDecompress(response: response, for: request, pipeline: pipeline) + pipeline.delegate?.shouldDecompress(response: response, for: request, pipeline: pipeline) ?? false } private func didReceiveDecompressedImage(_ response: ImageResponse, isCompleted: Bool) { @@ -149,19 +153,19 @@ final class TaskLoadImage: AsyncPipelineTask { } private func storeImageInDataCache(_ response: ImageResponse) { - guard let dataCache = pipeline.delegate.dataCache(for: request, pipeline: pipeline) else { + guard let dataCache = pipeline.delegate?.dataCache(for: request, pipeline: pipeline) else { return } let context = ImageEncodingContext(request: request, image: response.image, urlResponse: response.urlResponse) - let encoder = pipeline.delegate.imageEncoder(for: context, pipeline: pipeline) + let encoder = pipeline.delegate?.imageEncoder(for: context, pipeline: pipeline) let key = pipeline.cache.makeDataCacheKey(for: request) pipeline.configuration.imageEncodingQueue.addOperation { [weak pipeline, request] in guard let pipeline else { return } let encodedData = signpost("EncodeImage") { - encoder.encode(response.container, context: context) + encoder?.encode(response.container, context: context) } guard let data = encodedData, !data.isEmpty else { return } - pipeline.delegate.willCache(data: data, image: response.container, for: request, pipeline: pipeline) { + pipeline.delegate?.willCache(data: data, image: response.container, for: request, pipeline: pipeline) { guard let data = $0, !data.isEmpty else { return } // Important! Storing directly ignoring `ImageRequest.Options`. dataCache.storeData(data, for: key) // This is instant, writes are async From f13e85f37dd6c3e99b640274cb769eefa533ca7d Mon Sep 17 00:00:00 2001 From: Amol Prabhu Date: Thu, 8 Aug 2024 16:06:34 -0400 Subject: [PATCH 2/4] revert --- Sources/Nuke/Pipeline/ImagePipeline.swift | 16 ++++++++-------- Sources/Nuke/Tasks/TaskFetchOriginalData.swift | 10 +++++----- Sources/Nuke/Tasks/TaskFetchOriginalImage.swift | 2 +- Sources/Nuke/Tasks/TaskLoadImage.swift | 15 +++++++-------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Sources/Nuke/Pipeline/ImagePipeline.swift b/Sources/Nuke/Pipeline/ImagePipeline.swift index 1072ab2b2..1b8c88029 100644 --- a/Sources/Nuke/Pipeline/ImagePipeline.swift +++ b/Sources/Nuke/Pipeline/ImagePipeline.swift @@ -29,7 +29,7 @@ public final class ImagePipeline: @unchecked Sendable { /// Provides access to the underlying caching subsystems. public var cache: ImagePipeline.Cache { .init(pipeline: self) } - weak var delegate: (any ImagePipelineDelegate)? + let delegate: any ImagePipelineDelegate private var tasks = [ImageTask: TaskSubscription]() @@ -289,7 +289,7 @@ public final class ImagePipeline: @unchecked Sendable { let task = ImageTask(taskId: nextTaskId, request: request, isDataTask: isDataTask, pipeline: self, onEvent: onEvent) // Important to call it before `imageTaskStartCalled` if !isDataTask { - delegate?.imageTaskCreated(task, pipeline: self) + delegate.imageTaskCreated(task, pipeline: self) } task._task = Task { try await withUnsafeThrowingContinuation { continuation in @@ -317,7 +317,7 @@ public final class ImagePipeline: @unchecked Sendable { tasks[task] = worker.subscribe(priority: task.priority.taskPriority, subscriber: task) { [weak task] in task?._process($0) } - delegate?.imageTaskDidStart(task, pipeline: self) + delegate.imageTaskDidStart(task, pipeline: self) onTaskStarted?(task) } @@ -346,16 +346,16 @@ public final class ImagePipeline: @unchecked Sendable { } if !isDataTask { - delegate?.imageTask(task, didReceiveEvent: event, pipeline: self) + delegate.imageTask(task, didReceiveEvent: event, pipeline: self) switch event { case .progress(let progress): - delegate?.imageTask(task, didUpdateProgress: progress, pipeline: self) + delegate.imageTask(task, didUpdateProgress: progress, pipeline: self) case .preview(let response): - delegate?.imageTask(task, didReceivePreview: response, pipeline: self) + delegate.imageTask(task, didReceivePreview: response, pipeline: self) case .cancelled: - delegate?.imageTaskDidCancel(task, pipeline: self) + delegate.imageTaskDidCancel(task, pipeline: self) case .finished(let result): - delegate?.imageTask(task, didCompleteWithResult: result, pipeline: self) + delegate.imageTask(task, didCompleteWithResult: result, pipeline: self) } } } diff --git a/Sources/Nuke/Tasks/TaskFetchOriginalData.swift b/Sources/Nuke/Tasks/TaskFetchOriginalData.swift index b1f60f97e..3e21d66df 100644 --- a/Sources/Nuke/Tasks/TaskFetchOriginalData.swift +++ b/Sources/Nuke/Tasks/TaskFetchOriginalData.swift @@ -80,8 +80,8 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { signpost(self, "LoadImageData", .begin, "URL: \(urlRequest.url?.absoluteString ?? ""), resumable data: \(Formatter.bytes(resumableData?.data.count ?? 0))") - let dataLoader = pipeline.delegate?.dataLoader(for: request, pipeline: pipeline) - let dataTask = dataLoader?.loadData(with: urlRequest, didReceiveData: { [weak self] data, response in + let dataLoader = pipeline.delegate.dataLoader(for: request, pipeline: pipeline) + let dataTask = dataLoader.loadData(with: urlRequest, didReceiveData: { [weak self] data, response in guard let self else { return } self.pipeline.queue.async { self.dataTask(didReceiveData: data, response: response) @@ -99,7 +99,7 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { guard let self else { return } signpost(self, "LoadImageData", .end, "Cancelled") - dataTask?.cancel() + dataTask.cancel() finish() // Finish the operation! self.tryToSaveResumableData() @@ -170,11 +170,11 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { extension AsyncPipelineTask where Value == (Data, URLResponse?) { func storeDataInCacheIfNeeded(_ data: Data) { let request = makeSanitizedRequest() - guard let dataCache = pipeline.delegate?.dataCache(for: request, pipeline: pipeline), shouldStoreDataInDiskCache() else { + guard let dataCache = pipeline.delegate.dataCache(for: request, pipeline: pipeline), shouldStoreDataInDiskCache() else { return } let key = pipeline.cache.makeDataCacheKey(for: request) - pipeline.delegate?.willCache(data: data, image: nil, for: request, pipeline: pipeline) { + pipeline.delegate.willCache(data: data, image: nil, for: request, pipeline: pipeline) { guard let data = $0 else { return } // Important! Storing directly ignoring `ImageRequest.Options`. dataCache.storeData(data, for: key) diff --git a/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift b/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift index 062e91b36..385a23508 100644 --- a/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift +++ b/Sources/Nuke/Tasks/TaskFetchOriginalImage.swift @@ -62,7 +62,7 @@ final class TaskFetchOriginalImage: AsyncPipelineTask { if let decoder { return decoder } - let decoder = pipeline.delegate?.imageDecoder(for: context, pipeline: pipeline) + let decoder = pipeline.delegate.imageDecoder(for: context, pipeline: pipeline) self.decoder = decoder return decoder } diff --git a/Sources/Nuke/Tasks/TaskLoadImage.swift b/Sources/Nuke/Tasks/TaskLoadImage.swift index 6d4a38ed4..3e0f9b0be 100644 --- a/Sources/Nuke/Tasks/TaskLoadImage.swift +++ b/Sources/Nuke/Tasks/TaskLoadImage.swift @@ -27,7 +27,7 @@ final class TaskLoadImage: AsyncPipelineTask { private func decodeCachedData(_ data: Data) { let context = ImageDecodingContext(request: request, data: data, cacheType: .disk) - guard let decoder = pipeline.delegate?.imageDecoder(for: context, pipeline: pipeline) else { + guard let decoder = pipeline.delegate.imageDecoder(for: context, pipeline: pipeline) else { return didFinishDecoding(with: nil) } decode(context, decoder: decoder) { [weak self] in @@ -116,10 +116,9 @@ final class TaskLoadImage: AsyncPipelineTask { operation = pipeline.configuration.imageDecompressingQueue.add { [weak self] in guard let self else { return } let response = signpost(isCompleted ? "DecompressImage" : "DecompressProgressiveImage") { - self.pipeline.delegate?.decompress(response: response, request: self.request, pipeline: self.pipeline) + self.pipeline.delegate.decompress(response: response, request: self.request, pipeline: self.pipeline) } - guard let response else { return } self.pipeline.queue.async { [weak self] in guard let self else { return } self.operation = nil @@ -132,7 +131,7 @@ final class TaskLoadImage: AsyncPipelineTask { ImageDecompression.isDecompressionNeeded(for: response) && !request.options.contains(.skipDecompression) && hasDirectSubscribers && - pipeline.delegate?.shouldDecompress(response: response, for: request, pipeline: pipeline) ?? false + pipeline.delegate.shouldDecompress(response: response, for: request, pipeline: pipeline) } private func didReceiveDecompressedImage(_ response: ImageResponse, isCompleted: Bool) { @@ -153,19 +152,19 @@ final class TaskLoadImage: AsyncPipelineTask { } private func storeImageInDataCache(_ response: ImageResponse) { - guard let dataCache = pipeline.delegate?.dataCache(for: request, pipeline: pipeline) else { + guard let dataCache = pipeline.delegate.dataCache(for: request, pipeline: pipeline) else { return } let context = ImageEncodingContext(request: request, image: response.image, urlResponse: response.urlResponse) - let encoder = pipeline.delegate?.imageEncoder(for: context, pipeline: pipeline) + let encoder = pipeline.delegate.imageEncoder(for: context, pipeline: pipeline) let key = pipeline.cache.makeDataCacheKey(for: request) pipeline.configuration.imageEncodingQueue.addOperation { [weak pipeline, request] in guard let pipeline else { return } let encodedData = signpost("EncodeImage") { - encoder?.encode(response.container, context: context) + encoder.encode(response.container, context: context) } guard let data = encodedData, !data.isEmpty else { return } - pipeline.delegate?.willCache(data: data, image: response.container, for: request, pipeline: pipeline) { + pipeline.delegate.willCache(data: data, image: response.container, for: request, pipeline: pipeline) { guard let data = $0, !data.isEmpty else { return } // Important! Storing directly ignoring `ImageRequest.Options`. dataCache.storeData(data, for: key) // This is instant, writes are async From e97d20a44d87b1e93ad47f0a1fec30b5ab34c81a Mon Sep 17 00:00:00 2001 From: Amol Prabhu Date: Thu, 8 Aug 2024 16:07:31 -0400 Subject: [PATCH 3/4] revert --- Sources/Nuke/Pipeline/ImagePipeline+Cache.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift b/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift index 112170514..5637d3550 100644 --- a/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift +++ b/Sources/Nuke/Pipeline/ImagePipeline+Cache.swift @@ -189,7 +189,7 @@ extension ImagePipeline.Cache { /// Returns image cache (memory cache) key for the given request. public func makeImageCacheKey(for request: ImageRequest) -> ImageCacheKey { - if let customKey = pipeline.delegate?.cacheKey(for: request, pipeline: pipeline) { + if let customKey = pipeline.delegate.cacheKey(for: request, pipeline: pipeline) { return ImageCacheKey(key: customKey) } return ImageCacheKey(request: request) // Use the default key @@ -197,7 +197,7 @@ extension ImagePipeline.Cache { /// Returns data cache (disk cache) key for the given request. public func makeDataCacheKey(for request: ImageRequest) -> String { - if let customKey = pipeline.delegate?.cacheKey(for: request, pipeline: pipeline) { + if let customKey = pipeline.delegate.cacheKey(for: request, pipeline: pipeline) { return customKey } return "\(request.preferredImageId)\(request.thumbnail?.identifier ?? "")\(ImageProcessors.Composition(request.processors).identifier)" @@ -223,7 +223,7 @@ extension ImagePipeline.Cache { private func decodeImageData(_ data: Data, for request: ImageRequest) -> ImageContainer? { let context = ImageDecodingContext(request: request, data: data, cacheType: .disk) - guard let decoder = pipeline.delegate?.imageDecoder(for: context, pipeline: pipeline) else { + guard let decoder = pipeline.delegate.imageDecoder(for: context, pipeline: pipeline) else { return nil } return (try? decoder.decode(context))?.container @@ -231,16 +231,16 @@ extension ImagePipeline.Cache { private func encodeImage(_ image: ImageContainer, for request: ImageRequest) -> Data? { let context = ImageEncodingContext(request: request, image: image.image, urlResponse: nil) - let encoder = pipeline.delegate?.imageEncoder(for: context, pipeline: pipeline) - return encoder?.encode(image, context: context) + let encoder = pipeline.delegate.imageEncoder(for: context, pipeline: pipeline) + return encoder.encode(image, context: context) } private func imageCache(for request: ImageRequest) -> (any ImageCaching)? { - pipeline.delegate?.imageCache(for: request, pipeline: pipeline) + pipeline.delegate.imageCache(for: request, pipeline: pipeline) } private func dataCache(for request: ImageRequest) -> (any DataCaching)? { - pipeline.delegate?.dataCache(for: request, pipeline: pipeline) + pipeline.delegate.dataCache(for: request, pipeline: pipeline) } // MARK: Options From bb489fe8a184c5a5c51e5cd4bd752cc2063d7e68 Mon Sep 17 00:00:00 2001 From: Amol Prabhu Date: Thu, 8 Aug 2024 16:08:55 -0400 Subject: [PATCH 4/4] weak --- Sources/Nuke/Tasks/TaskFetchOriginalData.swift | 9 ++++++--- Sources/Nuke/Tasks/TaskFetchWithPublisher.swift | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Sources/Nuke/Tasks/TaskFetchOriginalData.swift b/Sources/Nuke/Tasks/TaskFetchOriginalData.swift index 3e21d66df..b62f8ef7e 100644 --- a/Sources/Nuke/Tasks/TaskFetchOriginalData.swift +++ b/Sources/Nuke/Tasks/TaskFetchOriginalData.swift @@ -54,7 +54,8 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { guard let self else { return finish() } - self.pipeline.queue.async { + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.loadData(urlRequest: urlRequest, finish: finish) } } @@ -83,14 +84,16 @@ final class TaskFetchOriginalData: AsyncPipelineTask<(Data, URLResponse?)> { let dataLoader = pipeline.delegate.dataLoader(for: request, pipeline: pipeline) let dataTask = dataLoader.loadData(with: urlRequest, didReceiveData: { [weak self] data, response in guard let self else { return } - self.pipeline.queue.async { + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.dataTask(didReceiveData: data, response: response) } }, completion: { [weak self] error in finish() // Finish the operation! guard let self else { return } signpost(self, "LoadImageData", .end, "Finished with size \(Formatter.bytes(self.data.count))") - self.pipeline.queue.async { + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.dataTaskDidFinish(error: error) } }) diff --git a/Sources/Nuke/Tasks/TaskFetchWithPublisher.swift b/Sources/Nuke/Tasks/TaskFetchWithPublisher.swift index 16d770c95..7f989cd0f 100644 --- a/Sources/Nuke/Tasks/TaskFetchWithPublisher.swift +++ b/Sources/Nuke/Tasks/TaskFetchWithPublisher.swift @@ -19,7 +19,8 @@ final class TaskFetchWithPublisher: AsyncPipelineTask<(Data, URLResponse?)> { guard let self else { return finish() } - self.pipeline.queue.async { + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.loadData { finish() } } } @@ -40,12 +41,14 @@ final class TaskFetchWithPublisher: AsyncPipelineTask<(Data, URLResponse?)> { let cancellable = publisher.sink(receiveCompletion: { [weak self] result in finish() // Finish the operation! guard let self else { return } - self.pipeline.queue.async { + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.dataTaskDidFinish(result) } }, receiveValue: { [weak self] data in guard let self else { return } - self.pipeline.queue.async { + self.pipeline.queue.async { [weak self] in + guard let self else { return } self.data.append(data) } })