From 7db1bfd3337e82c20b7f8ea225e68a0506acbc99 Mon Sep 17 00:00:00 2001 From: Fabian Thies Date: Tue, 20 Dec 2022 22:04:02 +0100 Subject: [PATCH 1/2] fix: Remove debug print statement in ImageLoader deinit --- Sources/AsyncImage/ImageLoader.swift | 4 +--- Sources/AsyncImage/ImageProcessor.swift | 8 ++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 Sources/AsyncImage/ImageProcessor.swift diff --git a/Sources/AsyncImage/ImageLoader.swift b/Sources/AsyncImage/ImageLoader.swift index 36904dd..7109ea8 100644 --- a/Sources/AsyncImage/ImageLoader.swift +++ b/Sources/AsyncImage/ImageLoader.swift @@ -14,9 +14,7 @@ final class ImageLoader: ObservableObject { self.scale = scale } - deinit { - print(true) - } + deinit {} func loadImage() { guard let url = url, asyncImagePhase.image == nil else { return } diff --git a/Sources/AsyncImage/ImageProcessor.swift b/Sources/AsyncImage/ImageProcessor.swift new file mode 100644 index 0000000..4511b96 --- /dev/null +++ b/Sources/AsyncImage/ImageProcessor.swift @@ -0,0 +1,8 @@ +// +// ImageProcessor.swift +// AsyncImage +// +// Created by Fabian Thies on 20.12.22. +// + +import Foundation From 018a4fffea025066d795ebb025c2769183f3fffb Mon Sep 17 00:00:00 2001 From: Fabian Thies Date: Tue, 20 Dec 2022 22:09:34 +0100 Subject: [PATCH 2/2] feat: New ImageProcessor to change the UIImage before returning the SwiftUI Image --- AsyncImage.xcodeproj/project.pbxproj | 4 ++++ Sources/AsyncImage/AsyncImage.swift | 10 ++++++---- Sources/AsyncImage/ImageLoader.swift | 9 ++++++++- Sources/AsyncImage/ImageProcessor.swift | 6 +++++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/AsyncImage.xcodeproj/project.pbxproj b/AsyncImage.xcodeproj/project.pbxproj index 4d22e0f..6061cb1 100644 --- a/AsyncImage.xcodeproj/project.pbxproj +++ b/AsyncImage.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 1F6284DD29525A5E0060AAD8 /* ImageProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F6284DC29525A5E0060AAD8 /* ImageProcessor.swift */; }; D4B7E90A2676204F006271B3 /* AsyncImageDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4B7E9092676204F006271B3 /* AsyncImageDemoApp.swift */; }; D4B7E90C2676204F006271B3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4B7E90B2676204F006271B3 /* ContentView.swift */; }; D4B7E90E26762050006271B3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D4B7E90D26762050006271B3 /* Assets.xcassets */; }; @@ -78,6 +79,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 1F6284DC29525A5E0060AAD8 /* ImageProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProcessor.swift; sourceTree = ""; }; "AsyncImage::AsyncImage::Product" /* AsyncImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AsyncImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; "AsyncImage::AsyncImageTests::Product" /* AsyncImageTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = AsyncImageTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D4B7E9072676204F006271B3 /* AsyncImageDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AsyncImageDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -207,6 +209,7 @@ OBJ_9 /* AsyncImage.swift */, OBJ_10 /* ImageLoader.swift */, OBJ_11 /* ImageService.swift */, + 1F6284DC29525A5E0060AAD8 /* ImageProcessor.swift */, D4B7E93F26774B8F006271B3 /* SessionDelegate.swift */, D4B7E93126766DB2006271B3 /* DataTask.swift */, OBJ_12 /* LRUCache.swift */, @@ -351,6 +354,7 @@ D4B7E94026774B8F006271B3 /* SessionDelegate.swift in Sources */, OBJ_26 /* AsyncImage.swift in Sources */, OBJ_27 /* ImageLoader.swift in Sources */, + 1F6284DD29525A5E0060AAD8 /* ImageProcessor.swift in Sources */, OBJ_28 /* ImageService.swift in Sources */, OBJ_29 /* LRUCache.swift in Sources */, ); diff --git a/Sources/AsyncImage/AsyncImage.swift b/Sources/AsyncImage/AsyncImage.swift index 7d5883b..fcf4df4 100644 --- a/Sources/AsyncImage/AsyncImage.swift +++ b/Sources/AsyncImage/AsyncImage.swift @@ -37,17 +37,18 @@ public struct AsyncImage: View { .onDisappear { loader.cancelDownload() } } - public init(url: URL, scale: CGFloat = 1) where Content == Image { - loader = ImageLoader(url: url, scale: scale) + public init(url: URL, scale: CGFloat = 1, processor: ImageProcessor? = nil) where Content == Image { + loader = ImageLoader(url: url, scale: scale, processor: processor) } public init( url: URL?, scale: CGFloat = 1, + processor: ImageProcessor? = nil, content: @escaping (Image) -> I, placeholder: @escaping () -> P ) where Content == _ConditionalContent { - self.init(url: url, scale: scale) { phase in + self.init(url: url, scale: scale, processor: processor) { phase in if let image = phase.image { content(image) } else { @@ -59,10 +60,11 @@ public struct AsyncImage: View { public init( url: URL?, scale: CGFloat = 1, + processor: ImageProcessor? = nil, transaction: Transaction = Transaction(), @ViewBuilder content: @escaping (AsyncImagePhase) -> Content ) { self.content = content - loader = ImageLoader(url: url, scale: scale) + loader = ImageLoader(url: url, scale: scale, processor: processor) } } diff --git a/Sources/AsyncImage/ImageLoader.swift b/Sources/AsyncImage/ImageLoader.swift index 7109ea8..09c7ea8 100644 --- a/Sources/AsyncImage/ImageLoader.swift +++ b/Sources/AsyncImage/ImageLoader.swift @@ -7,11 +7,13 @@ final class ImageLoader: ObservableObject { @Published var asyncImagePhase = AsyncImagePhase.empty let scale: CGFloat let url: URL? + let processor: ImageProcessor? var downloadTask: DownloadTask? - init(url: URL?, scale: CGFloat) { + init(url: URL?, scale: CGFloat, processor: ImageProcessor?) { self.url = url self.scale = scale + self.processor = processor } deinit {} @@ -25,6 +27,11 @@ final class ImageLoader: ObservableObject { guard let self = self else { return } switch result { case .success(let image): + var image = image + if let processor = self.processor { + // Processing the fetched image here to keep the cached image untouched. + image = processor.process(image: image) + } self.asyncImagePhase = .success(Image(uiImage: image)) case .failure(let error): if error.isCanceled { return } diff --git a/Sources/AsyncImage/ImageProcessor.swift b/Sources/AsyncImage/ImageProcessor.swift index 4511b96..e231672 100644 --- a/Sources/AsyncImage/ImageProcessor.swift +++ b/Sources/AsyncImage/ImageProcessor.swift @@ -5,4 +5,8 @@ // Created by Fabian Thies on 20.12.22. // -import Foundation +import UIKit + +public protocol ImageProcessor { + func process(image: UIImage) -> UIImage +}