Merge pull request #316 from SDWebImage/try_fix_watchOS_switch_nil_url
Trying to move the initial state setup before `onAppear` to fix the watchOS switching url or any other state issue
This commit is contained in:
commit
3876ce2a60
|
@ -7,7 +7,6 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3243AFE62AA37EFF0049A43B /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B79C9428DB40430088C432 /* SwiftUICompatibility.swift */; };
|
||||
3243AFE72AA37EFF0049A43B /* WebImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C43DDE22FD54C600BE87F5 /* WebImage.swift */; };
|
||||
3243AFE82AA37EFF0049A43B /* ImagePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CBA77E25E4D7D800C6A8DC /* ImagePlayer.swift */; };
|
||||
3243AFE92AA37EFF0049A43B /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
|
||||
|
@ -26,10 +25,6 @@
|
|||
326E480C23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
|
||||
326E480D23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; };
|
||||
329885EE2AA37FCB0071F2BA /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 329885ED2AA37FCB0071F2BA /* SDWebImage.framework */; };
|
||||
32B79C9528DB40430088C432 /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B79C9428DB40430088C432 /* SwiftUICompatibility.swift */; };
|
||||
32B79C9628DB40430088C432 /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B79C9428DB40430088C432 /* SwiftUICompatibility.swift */; };
|
||||
32B79C9728DB40430088C432 /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B79C9428DB40430088C432 /* SwiftUICompatibility.swift */; };
|
||||
32B79C9828DB40430088C432 /* SwiftUICompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B79C9428DB40430088C432 /* SwiftUICompatibility.swift */; };
|
||||
32B933E523659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; };
|
||||
32B933E623659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; };
|
||||
32B933E723659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; };
|
||||
|
@ -83,7 +78,6 @@
|
|||
326B84812363350C0011BDFB /* Indicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Indicator.swift; sourceTree = "<group>"; };
|
||||
326E480923431C0F00C633E9 /* ImageViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewWrapper.swift; sourceTree = "<group>"; };
|
||||
329885ED2AA37FCB0071F2BA /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/visionOS/SDWebImage.framework; sourceTree = "<group>"; };
|
||||
32B79C9428DB40430088C432 /* SwiftUICompatibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUICompatibility.swift; sourceTree = "<group>"; };
|
||||
32B933E423659A1900BB7CAD /* Transition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transition.swift; sourceTree = "<group>"; };
|
||||
32C43DCC22FD540D00BE87F5 /* SDWebImageSwiftUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageSwiftUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32C43DDC22FD54C600BE87F5 /* ImageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageManager.swift; sourceTree = "<group>"; };
|
||||
|
@ -221,7 +215,6 @@
|
|||
32C43DDE22FD54C600BE87F5 /* WebImage.swift */,
|
||||
32C43DDF22FD54C600BE87F5 /* AnimatedImage.swift */,
|
||||
32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */,
|
||||
32B79C9428DB40430088C432 /* SwiftUICompatibility.swift */,
|
||||
326E480923431C0F00C633E9 /* ImageViewWrapper.swift */,
|
||||
32D26A012446B546005905DA /* Image.swift */,
|
||||
);
|
||||
|
@ -491,7 +484,6 @@
|
|||
3243AFEB2AA37EFF0049A43B /* AnimatedImage.swift in Sources */,
|
||||
3243AFE82AA37EFF0049A43B /* ImagePlayer.swift in Sources */,
|
||||
3243AFED2AA37EFF0049A43B /* SDWebImageSwiftUI.swift in Sources */,
|
||||
3243AFE62AA37EFF0049A43B /* SwiftUICompatibility.swift in Sources */,
|
||||
3243AFEE2AA37F010049A43B /* Indicator.swift in Sources */,
|
||||
3243AFEA2AA37EFF0049A43B /* Image.swift in Sources */,
|
||||
);
|
||||
|
@ -507,7 +499,6 @@
|
|||
326B84822363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3222FD5DE100BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480A23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
32B79C9528DB40430088C432 /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E1622FD583700BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E1822FD583700BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A022446B546005905DA /* Image.swift in Sources */,
|
||||
|
@ -524,7 +515,6 @@
|
|||
326B84832363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3322FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480B23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
32B79C9628DB40430088C432 /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E1922FD583700BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E1B22FD583700BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A032446B546005905DA /* Image.swift in Sources */,
|
||||
|
@ -541,7 +531,6 @@
|
|||
326B84842363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3422FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480C23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
32B79C9728DB40430088C432 /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E1C22FD583800BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E1E22FD583800BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A042446B546005905DA /* Image.swift in Sources */,
|
||||
|
@ -558,7 +547,6 @@
|
|||
326B84852363350C0011BDFB /* Indicator.swift in Sources */,
|
||||
32C43E3522FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */,
|
||||
326E480D23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */,
|
||||
32B79C9828DB40430088C432 /* SwiftUICompatibility.swift in Sources */,
|
||||
32C43E1F22FD583800BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E2122FD583800BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A052446B546005905DA /* Image.swift in Sources */,
|
||||
|
|
|
@ -15,17 +15,47 @@ import SDWebImage
|
|||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||
public final class ImageManager : ObservableObject {
|
||||
/// loaded image, note when progressive loading, this will published multiple times with different partial image
|
||||
@Published public var image: PlatformImage?
|
||||
public var image: PlatformImage? {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// loaded image data, may be nil if hit from memory cache. This will only published once even on incremental image loading
|
||||
@Published public var imageData: Data?
|
||||
public var imageData: Data? {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// loaded image cache type, .none means from network
|
||||
@Published public var cacheType: SDImageCacheType = .none
|
||||
public var cacheType: SDImageCacheType = .none {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// loading error, you can grab the error code and reason listed in `SDWebImageErrorDomain`, to provide a user interface about the error reason
|
||||
@Published public var error: Error?
|
||||
public var error: Error? {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// true means during incremental loading
|
||||
@Published public var isIncremental: Bool = false
|
||||
public var isIncremental: Bool = false {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// A observed object to pass through the image manager loading status to indicator
|
||||
@Published public var indicatorStatus = IndicatorStatus()
|
||||
public var indicatorStatus = IndicatorStatus()
|
||||
|
||||
weak var currentOperation: SDWebImageOperation? = nil
|
||||
|
||||
|
@ -51,8 +81,8 @@ public final class ImageManager : ObservableObject {
|
|||
return
|
||||
}
|
||||
currentURL = url
|
||||
indicatorStatus.isLoading = true
|
||||
indicatorStatus.progress = 0
|
||||
self.indicatorStatus.isLoading = true
|
||||
self.indicatorStatus.progress = 0
|
||||
currentOperation = manager.loadImage(with: url, options: options, context: context, progress: { [weak self] (receivedSize, expectedSize, _) in
|
||||
guard let self = self else {
|
||||
return
|
||||
|
@ -63,9 +93,7 @@ public final class ImageManager : ObservableObject {
|
|||
} else {
|
||||
progress = 0
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.indicatorStatus.progress = progress
|
||||
}
|
||||
self.progressBlock?(receivedSize, expectedSize)
|
||||
}) { [weak self] (image, data, error, cacheType, finished, _) in
|
||||
guard let self = self else {
|
||||
|
|
|
@ -28,9 +28,21 @@ public struct Indicator<T> where T : View {
|
|||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||
public class IndicatorStatus : ObservableObject {
|
||||
/// whether indicator is loading or not
|
||||
@Published var isLoading: Bool = false
|
||||
var isLoading: Bool = false {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// indicator progress, should only be used for indicator binding, value between [0.0, 1.0]
|
||||
@Published var progress: Double = 0
|
||||
var progress: Double = 0 {
|
||||
didSet {
|
||||
DispatchQueue.main.async {
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A implementation detail View Modifier with indicator
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) DreamPiggy <lizhuoli1126@126.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
#if !os(watchOS)
|
||||
|
||||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||
struct PlatformAppear: PlatformViewRepresentable {
|
||||
let appearAction: () -> Void
|
||||
let disappearAction: () -> Void
|
||||
|
||||
#if os(iOS) || os(tvOS) || os(visionOS)
|
||||
func makeUIView(context: Context) -> some UIView {
|
||||
let view = PlatformAppearView()
|
||||
view.appearAction = appearAction
|
||||
view.disappearAction = disappearAction
|
||||
return view
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIViewType, context: Context) {}
|
||||
#endif
|
||||
#if os(macOS)
|
||||
func makeNSView(context: Context) -> some NSView {
|
||||
let view = PlatformAppearView()
|
||||
view.appearAction = appearAction
|
||||
view.disappearAction = disappearAction
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: NSViewType, context: Context) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||
class PlatformAppearView: PlatformView {
|
||||
var appearAction: () -> Void = {}
|
||||
var disappearAction: () -> Void = {}
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
override func willMove(toWindow newWindow: UIWindow?) {
|
||||
if newWindow != nil {
|
||||
DispatchQueue.main.async {
|
||||
self.appearAction()
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.disappearAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(macOS)
|
||||
override func viewWillMove(toWindow newWindow: NSWindow?) {
|
||||
if newWindow != nil {
|
||||
DispatchQueue.main.async {
|
||||
self.appearAction()
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.disappearAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||
extension View {
|
||||
/// Used UIKit/AppKit behavior to detect the SwiftUI view's visibility.
|
||||
/// This hack is because of SwiftUI 1.0/2.0 buggy behavior. The built-in `onAppear` and `onDisappear` is so massive on some cases. Where UIKit/AppKit is solid.
|
||||
/// - Parameters:
|
||||
/// - appear: The action when view appears
|
||||
/// - disappear: The action when view disappears
|
||||
/// - Returns: Some view
|
||||
func onPlatformAppear(appear: @escaping () -> Void = {}, disappear: @escaping () -> Void = {}) -> some View {
|
||||
#if os(iOS) || os(tvOS) || os(macOS)
|
||||
return self.background(PlatformAppear(appearAction: appear, disappearAction: disappear))
|
||||
#else
|
||||
return self.onAppear(perform: appear).onDisappear(perform: disappear)
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -163,26 +163,22 @@ public struct WebImage<Content> : View where Content: View {
|
|||
}
|
||||
} else {
|
||||
content((imageManager.error != nil) ? .failure(imageManager.error!) : .empty)
|
||||
setupPlaceholder()
|
||||
setupInitialState()
|
||||
// Load Logic
|
||||
.onPlatformAppear(appear: {
|
||||
self.setupManager()
|
||||
if (self.imageManager.error == nil) {
|
||||
// Load remote image when first appear
|
||||
self.imageManager.load(url: imageModel.url, options: imageModel.options, context: imageModel.context)
|
||||
}
|
||||
.onAppear {
|
||||
guard self.imageConfiguration.retryOnAppear else { return }
|
||||
// When using prorgessive loading, the new partial image will cause onAppear. Filter this case
|
||||
if self.imageManager.error != nil && !self.imageManager.isIncremental {
|
||||
self.imageManager.load(url: imageModel.url, options: imageModel.options, context: imageModel.context)
|
||||
}
|
||||
}, disappear: {
|
||||
}
|
||||
.onDisappear {
|
||||
guard self.imageConfiguration.cancelOnDisappear else { return }
|
||||
// When using prorgessive loading, the previous partial image will cause onDisappear. Filter this case
|
||||
if self.imageManager.error != nil && !self.imageManager.isIncremental {
|
||||
self.imageManager.cancel()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,6 +324,16 @@ public struct WebImage<Content> : View where Content: View {
|
|||
}
|
||||
}
|
||||
|
||||
/// Initial state management (update when imageModel.url changed)
|
||||
func setupInitialState() -> some View {
|
||||
self.setupManager()
|
||||
if (self.imageManager.error == nil) {
|
||||
// Load remote image when first appear
|
||||
self.imageManager.load(url: imageModel.url, options: imageModel.options, context: imageModel.context)
|
||||
}
|
||||
return setupPlaceholder()
|
||||
}
|
||||
|
||||
/// Placeholder View Support
|
||||
func setupPlaceholder() -> some View {
|
||||
let result = content((imageManager.error != nil) ? .failure(imageManager.error!) : .empty)
|
||||
|
|
Loading…
Reference in New Issue