From ebd0535fa52d16a9a20e2a235bace8c5cbf361ac Mon Sep 17 00:00:00 2001 From: onevcat Date: Mon, 2 Jan 2023 10:06:56 +0900 Subject: [PATCH 1/2] An option to allow load before view appear --- Sources/SwiftUI/ImageContext.swift | 2 ++ Sources/SwiftUI/KFImageOptions.swift | 5 +++++ Sources/SwiftUI/KFImageRenderer.swift | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftUI/ImageContext.swift b/Sources/SwiftUI/ImageContext.swift index 7275f0eb8..f10f463c1 100644 --- a/Sources/SwiftUI/ImageContext.swift +++ b/Sources/SwiftUI/ImageContext.swift @@ -46,6 +46,8 @@ extension KFImage { let onSuccessDelegate = Delegate() let onProgressDelegate = Delegate<(Int64, Int64), Void>() + var startLoadingBeforeViewAppear: Bool = false + init(source: Source?) { self.source = source } diff --git a/Sources/SwiftUI/KFImageOptions.swift b/Sources/SwiftUI/KFImageOptions.swift index e553b2aa9..39b622b22 100644 --- a/Sources/SwiftUI/KFImageOptions.swift +++ b/Sources/SwiftUI/KFImageOptions.swift @@ -134,5 +134,10 @@ extension KFImageProtocol { context.options.transition = .fade(duration) return self } + + public func startLoadingBeforeViewAppear(_ flag: Bool = true) -> Self { + context.startLoadingBeforeViewAppear = flag + return self + } } #endif diff --git a/Sources/SwiftUI/KFImageRenderer.swift b/Sources/SwiftUI/KFImageRenderer.swift index 3398389e0..0bcde946a 100644 --- a/Sources/SwiftUI/KFImageRenderer.swift +++ b/Sources/SwiftUI/KFImageRenderer.swift @@ -37,7 +37,11 @@ struct KFImageRenderer : View where HoldingView: KFImageHoldingView let context: KFImage.Context var body: some View { - ZStack { + if context.startLoadingBeforeViewAppear && !binder.loadingOrSucceeded { + DispatchQueue.main.async { binder.start(context: context) } + } + + return ZStack { context.configurations .reduce(HoldingView.created(from: binder.loadedImage, context: context)) { current, config in config(current) From ef64d518768f408ee02655772be262fca9059180 Mon Sep 17 00:00:00 2001 From: onevcat Date: Sat, 7 Jan 2023 23:33:37 +0900 Subject: [PATCH 2/2] Add documentation for startLoadingBeforeViewAppear --- Sources/General/KFOptionsSetter.swift | 3 +-- Sources/SwiftUI/KFImageOptions.swift | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Sources/General/KFOptionsSetter.swift b/Sources/General/KFOptionsSetter.swift index c77359386..9a077539a 100644 --- a/Sources/General/KFOptionsSetter.swift +++ b/Sources/General/KFOptionsSetter.swift @@ -442,8 +442,7 @@ extension KFOptionSetter { /// to form a processor pipeline. /// - Returns: A `Self` value with changes applied. /// - /// - Note: - /// To append processors to current ones instead of replacing them all, concatenate them by `|>`, then use + /// - Note: To append processors to current ones instead of replacing them all, concatenate them by `|>`, then use /// `appendProcessor(_:)`. public func setProcessors(_ processors: [ImageProcessor]) -> Self { switch processors.count { diff --git a/Sources/SwiftUI/KFImageOptions.swift b/Sources/SwiftUI/KFImageOptions.swift index 39b622b22..a63d90976 100644 --- a/Sources/SwiftUI/KFImageOptions.swift +++ b/Sources/SwiftUI/KFImageOptions.swift @@ -135,6 +135,21 @@ extension KFImageProtocol { return self } + /// Sets whether to start the image loading before the view actually appears. + /// + /// By default, Kingfisher performs a lazy loading for `KFImage`. The image loading won't start until the view's + /// `onAppear` is called. However, sometimes you may want to trigger an aggressive loading for the view. By enabling + /// this, the `KFImage` will try to load the view when its `body` is evaluated when the image loading is not yet + /// started or a previous loading did fail. + /// + /// - Parameter flag: Whether the image loading should happen before view appear. Default is `true`. + /// - Returns: A `KFImage` with changes applied. + /// + /// - Note: This is a temporary workaround for an issue from iOS 16, where the SwiftUI view's `onAppear` is not + /// called when it is deeply embedded inside a `List` or `ForEach`. + /// See [#1988](https://github.com/onevcat/Kingfisher/issues/1988). It may cause performance regression, especially + /// if you have a lot of images to load in the view. Use it as your own risk. + /// public func startLoadingBeforeViewAppear(_ flag: Bool = true) -> Self { context.startLoadingBeforeViewAppear = flag return self