Skip to content

Commit 88e4dea

Browse files
committed
Make the ImageManager obseable
1 parent 3d43d8b commit 88e4dea

File tree

2 files changed

+61
-14
lines changed

2 files changed

+61
-14
lines changed

SDWebImageSwiftUI/Classes/ImageManager.swift

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@
99
import SwiftUI
1010
import SDWebImage
1111

12+
/// A Image observable object for handle image load process. This drive the Source of Truth for image loading status.
13+
/// You can use `@ObservedObject` to associate each instance of manager to your View type, which update your view's body from SwiftUI framework when image was loaded.
1214
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
13-
class ImageManager : ObservableObject, IndicatorReportable {
14-
@Published var image: PlatformImage? // loaded image, note when progressive loading, this will published multiple times with different partial image
15-
@Published var isLoading: Bool = false // whether network is loading or cache is querying, should only be used for indicator binding
16-
@Published var progress: Double = 0 // network progress, should only be used for indicator binding
15+
public final class ImageManager : ObservableObject {
16+
/// loaded image, note when progressive loading, this will published multiple times with different partial image
17+
@Published public var image: PlatformImage?
18+
/// whether network is loading or cache is querying, should only be used for indicator binding
19+
@Published public var isLoading: Bool = false
20+
/// network progress, should only be used for indicator binding
21+
@Published public var progress: Double = 0
22+
/// true means during incremental loading
23+
@Published public var isIncremental: Bool = false
1724

1825
var manager: SDWebImageManager
1926
weak var currentOperation: SDWebImageOperation? = nil
20-
var isSuccess: Bool = false // true means request for this URL is ended forever, load() do nothing
21-
var isIncremental: Bool = false // true means during incremental loading
2227
var isFirstLoad: Bool = true // false after first call `load()`
2328

2429
var url: URL?
@@ -28,7 +33,11 @@ class ImageManager : ObservableObject, IndicatorReportable {
2833
var failureBlock: ((Error) -> Void)?
2934
var progressBlock: ((Int, Int) -> Void)?
3035

31-
init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) {
36+
/// Create a image manager for loading the specify url, with custom options and context.
37+
/// - Parameter url: The image url
38+
/// - Parameter options: The options to use when downloading the image. See `SDWebImageOptions` for the possible values.
39+
/// - Parameter context: A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
40+
public init(url: URL?, options: SDWebImageOptions = [], context: [SDWebImageContextOption : Any]? = nil) {
3241
self.url = url
3342
self.options = options
3443
self.context = context
@@ -39,7 +48,8 @@ class ImageManager : ObservableObject, IndicatorReportable {
3948
}
4049
}
4150

42-
func load() {
51+
/// Start to load the url operation
52+
public func load() {
4353
isFirstLoad = false
4454
if currentOperation != nil {
4555
return
@@ -76,7 +86,6 @@ class ImageManager : ObservableObject, IndicatorReportable {
7686
self.isLoading = false
7787
self.progress = 1
7888
if let image = image {
79-
self.isSuccess = true
8089
self.successBlock?(image, cacheType)
8190
} else {
8291
self.failureBlock?(error ?? NSError())
@@ -85,9 +94,46 @@ class ImageManager : ObservableObject, IndicatorReportable {
8594
}
8695
}
8796

88-
func cancel() {
89-
currentOperation?.cancel()
90-
currentOperation = nil
97+
/// Cancel the current url loading
98+
public func cancel() {
99+
if let operation = currentOperation {
100+
operation.cancel()
101+
currentOperation = nil
102+
isLoading = false
103+
}
91104
}
92105

93106
}
107+
108+
// Completion Handler
109+
extension ImageManager {
110+
/// Provide the action when image load fails.
111+
/// - Parameters:
112+
/// - action: The action to perform. The first arg is the error during loading. If `action` is `nil`, the call has no effect.
113+
/// - Returns: A view that triggers `action` when this image load fails.
114+
public func onFailure(perform action: ((Error) -> Void)? = nil) -> ImageManager {
115+
self.failureBlock = action
116+
return self
117+
}
118+
119+
/// Provide the action when image load successes.
120+
/// - Parameters:
121+
/// - action: The action to perform. The first arg is the loaded image, the second arg is the cache type loaded from. If `action` is `nil`, the call has no effect.
122+
/// - Returns: A view that triggers `action` when this image load successes.
123+
public func onSuccess(perform action: ((PlatformImage, SDImageCacheType) -> Void)? = nil) -> ImageManager {
124+
self.successBlock = action
125+
return self
126+
}
127+
128+
/// Provide the action when image load progress changes.
129+
/// - Parameters:
130+
/// - action: The action to perform. The first arg is the received size, the second arg is the total size, all in bytes. If `action` is `nil`, the call has no effect.
131+
/// - Returns: A view that triggers `action` when this image load successes.
132+
public func onProgress(perform action: ((Int, Int) -> Void)? = nil) -> ImageManager {
133+
self.progressBlock = action
134+
return self
135+
}
136+
}
137+
138+
// Indicator Reportor
139+
extension ImageManager: IndicatorReportable {}

SDWebImageSwiftUI/Classes/WebImage.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,15 @@ public struct WebImage : View {
120120
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
121121
.onAppear {
122122
guard self.retryOnAppear else { return }
123-
if !self.imageManager.isSuccess {
123+
// When using prorgessive loading, the new partial image will cause onAppear. Filter this case
124+
if self.imageManager.image == nil && !self.imageManager.isIncremental {
124125
self.imageManager.load()
125126
}
126127
}
127128
.onDisappear {
128129
guard self.cancelOnDisappear else { return }
129130
// When using prorgessive loading, the previous partial image will cause onDisappear. Filter this case
130-
if !self.imageManager.isSuccess && !self.imageManager.isIncremental {
131+
if self.imageManager.image == nil && !self.imageManager.isIncremental {
131132
self.imageManager.cancel()
132133
}
133134
}

0 commit comments

Comments
 (0)