Skip to content

Commit 0dcefe5

Browse files
authored
Merge pull request #92 from SDWebImage/fix_query_image_extra_times
Fix the issue when using WebImage with some transition like scaleEffect, each time the new state update will cause unused image fetching
2 parents 0b11cce + ffeea1a commit 0dcefe5

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

Example/SDWebImageSwiftUIDemo/DetailView.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct DetailView: View {
3838
let url: String
3939
let animated: Bool
4040
@State var isAnimating: Bool = true
41-
@State var lastScaleValue: CGFloat = 1.0
41+
@State var lastScale: CGFloat = 1.0
4242
@State var scale: CGFloat = 1.0
4343
@Environment(\.presentationMode) var presentationMode
4444
@EnvironmentObject var settings: UserSettings
@@ -75,12 +75,12 @@ struct DetailView: View {
7575
return contentView()
7676
.scaleEffect(self.scale)
7777
.gesture(MagnificationGesture(minimumScaleDelta: 0.1).onChanged { value in
78-
let delta = value / self.lastScaleValue
79-
self.lastScaleValue = value
78+
let delta = value / self.lastScale
79+
self.lastScale = value
8080
let newScale = self.scale * delta
8181
self.scale = min(max(newScale, 0.5), 2)
8282
}.onEnded { value in
83-
self.lastScaleValue = 1.0
83+
self.lastScale = 1.0
8484
})
8585
#endif
8686
#if os(tvOS)

SDWebImageSwiftUI/Classes/ImageManager.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public final class ImageManager : ObservableObject {
2727
var manager: SDWebImageManager
2828
weak var currentOperation: SDWebImageOperation? = nil
2929
var isFirstLoad: Bool = true // false after first call `load()`
30+
var isFirstPrefetch: Bool = true // false after first call `prefetch()`
3031

3132
var url: URL?
3233
var options: SDWebImageOptions
@@ -106,6 +107,45 @@ public final class ImageManager : ObservableObject {
106107
}
107108
}
108109

110+
/// Prefetch the initial state of image, currently query the memory cache only
111+
func prefetch() {
112+
isFirstPrefetch = false
113+
// Use the options processor if provided
114+
let options = self.options
115+
var context = self.context
116+
if let result = manager.optionsProcessor?.processedResult(for: url, options: options, context: context) {
117+
context = result.context
118+
}
119+
// TODO: Remove transformer for cache calculation before SDWebImage 5.7.0, this is bug. Remove later
120+
let transformer = (context?[.imageTransformer] as? SDImageTransformer) ?? manager.transformer
121+
context?[.imageTransformer] = nil
122+
// TODO: before SDWebImage 5.7.0, this is the SPI. Remove later
123+
var key = manager.perform(Selector(("cacheKeyForURL:context:")), with: url, with: context)?.takeUnretainedValue() as? String
124+
if let transformer = transformer {
125+
key = SDTransformedKeyForKey(key, transformer.transformerKey)
126+
}
127+
// Shortcut for built-in cache
128+
if let imageCache = manager.imageCache as? SDImageCache {
129+
let image = imageCache.imageFromMemoryCache(forKey: key)
130+
self.image = image
131+
if let image = image {
132+
self.successBlock?(image, .memory)
133+
}
134+
} else {
135+
// This callback is synchronzied
136+
manager.imageCache.containsImage(forKey: key, cacheType: .memory) { [unowned self] (cacheType) in
137+
if cacheType == .memory {
138+
self.manager.imageCache.queryImage(forKey: key, options: options, context: context) { [unowned self] (image, data, cacheType) in
139+
self.image = image
140+
if let image = image {
141+
self.successBlock?(image, cacheType)
142+
}
143+
}
144+
}
145+
}
146+
}
147+
}
148+
109149
}
110150

111151
// Completion Handler

SDWebImageSwiftUI/Classes/WebImage.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,10 @@ public struct WebImage : View {
6060
}
6161

6262
public var body: some View {
63-
// load remote image when first called `body`, SwiftUI sometimes will create a new View struct without calling `onAppear` (like enter EditMode) :)
64-
// this can ensure we load the image, and display image synchronously when memory cache hit to avoid flashing
65-
// called once per struct, SDWebImage take care of the duplicated query
66-
if imageManager.isFirstLoad {
67-
imageManager.load()
63+
// this prefetch the memory cache of image, to immediately render it on screen
64+
// this solve the case when `onAppear` not been called, for example, some transaction indeterminate state, SwiftUI :)
65+
if imageManager.isFirstPrefetch {
66+
self.imageManager.prefetch()
6867
}
6968
return Group {
7069
if imageManager.image != nil {
@@ -109,6 +108,11 @@ public struct WebImage : View {
109108
setupPlaceholder()
110109
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
111110
.onAppear {
111+
// load remote image when first appear
112+
if self.imageManager.isFirstLoad {
113+
self.imageManager.load()
114+
return
115+
}
112116
guard self.retryOnAppear else { return }
113117
// When using prorgessive loading, the new partial image will cause onAppear. Filter this case
114118
if self.imageManager.image == nil && !self.imageManager.isIncremental {

0 commit comments

Comments
 (0)