onevcat / Kingfisher

A lightweight, pure-Swift library for downloading and caching images from the web.
MIT License
23.43k stars 2.66k forks source link

Using "startLoadingBeforeViewAppear()" leads to the image always loading the next run loop #2040

Open BobbyRohweder opened 1 year ago

BobbyRohweder commented 1 year ago

Issue Description

What

When a SwiftUI KFImage is used with "startLoadingBeforeViewAppear()", the image will always load the next run loop, which causes the placeholder to show and the UI to flash.

This was likely caused by the "loading" state in https://github.com/onevcat/Kingfisher/pull/2036 combined with the async dispatch to main, DispatchQueue.main.async { binder.start(context: context) }

Reproduce

Have the asset already in memory, switch to a view with the image, and the blue still shows.

Remove ".startLoadingBeforeViewAppear()" and the blue does not show, since it can display is synchronously when the view is created and displayed.

KFImage(someImageURL)
    .startLoadingBeforeViewAppear()
    .placeholder { Rectangle().fill(Color.blue) }

Other Comment

Kingfisher version: 7.6.2 iOS version: 16.X

onevcat commented 1 year ago

That flag was created to fix a multiple start(context:) invocation. With the original issue #1988 existing, I guess it might be the best thing we can do now (We do not have the choice to hook up to the SwiftUI's view appear, but also have to not modify the @Published value in view's body).

The good news is, I heard that Xcode 14.3 and iOS 16.4 SDK finally fixed the original issue, and the startLoadingBeforeViewAppear will be not necessary when deploying to the later iOS versions. I do not yet have a chance to try the latest iOS version, but I will do that soon and see what to do with this and the ugly startLoadingBeforeViewAppear workaround.