admin管理员组文章数量:1355703
AsyncImage(url: URL(string: profilImgUrl)) { phase in
switch phase {
case .empty:
ProgressView()
.scaleEffect(x: 1.5, y: 1.5, anchor: .center)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 36)
case .success(let image):
image.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 36)
.cornerRadius(50)
case .failure:
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
@unknown default:
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
}
The case .failure
gets triggered pretty often, even though the profilImgUrl
is 100% valid.
In the Android version, I've set how often it needs to be tried again when the image fails to load and in the end, the images are shown 100% of the time, is it possible to do it in SwiftUI too? If not, what workaround could I do?
AsyncImage(url: URL(string: profilImgUrl)) { phase in
switch phase {
case .empty:
ProgressView()
.scaleEffect(x: 1.5, y: 1.5, anchor: .center)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 36)
case .success(let image):
image.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 36)
.cornerRadius(50)
case .failure:
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
@unknown default:
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
}
The case .failure
gets triggered pretty often, even though the profilImgUrl
is 100% valid.
In the Android version, I've set how often it needs to be tried again when the image fails to load and in the end, the images are shown 100% of the time, is it possible to do it in SwiftUI too? If not, what workaround could I do?
Share Improve this question asked Mar 29 at 19:19 TheGreatCornholioTheGreatCornholio 1,5451 gold badge23 silver badges49 bronze badges 2 |1 Answer
Reset to default 1You could try this approach using a retryCount
and func retryImage()
, as shown in this example code:
struct ContentView: View {
var body: some View {
AutoRetryAsyncImageView(originalUrl: URL(string: "https://example/image.jpg"))
}
}
struct AutoRetryAsyncImageView: View {
let originalUrl: URL?
let maxRetries: Int = 3
@State private var retryCount = 0
@State private var imageUrl: URL?
var body: some View {
VStack {
AsyncImage(url: imageUrl) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
image.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 36)
.cornerRadius(50)
case .failure:
if retryCount < maxRetries {
ProgressView("Retrying... \(retryCount)/\(maxRetries)")
.onAppear { retryImage() }
} else {
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
}
@unknown default:
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
}
}
}
.onAppear {
imageUrl = originalUrl
}
}
private func retryImage() {
guard retryCount < maxRetries else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
retryCount += 1
imageUrl = nil // clear url
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
imageUrl = originalUrl // force reload
}
}
}
}
EDIT-1:
you can also try this alternative approach having the parent view control the retries.
struct ContentView: View {
@State private var retryCount = 0
let maxRetries: Int = 3
var body: some View {
AutoRetryAsyncImageView(maxRetries: maxRetries, retryCount: $retryCount)
.onChange(of: retryCount) {
print("---> retryCount: \(retryCount)")
guard retryCount < maxRetries else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
retryCount += 1
}
}
}
}
struct AutoRetryAsyncImageView: View {
let maxRetries: Int
@Binding var retryCount: Int
let imageUrl: URL? = URL(string: "https://example/image.jpg")
var body: some View {
VStack {
AsyncImage(url: imageUrl) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
image.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 36)
.cornerRadius(50)
case .failure:
if retryCount < maxRetries {
ProgressView("Retrying... \(retryCount)/\(maxRetries)")
.onAppear {
retryCount += 1
}
} else {
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
}
@unknown default:
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit).frame(height: 36)
.cornerRadius(50)
.foregroundColor(Color.gray)
}
}
}
}
}
本文标签: iosSwiftUI AsyncImagetry again on image loading failureStack Overflow
版权声明:本文标题:ios - SwiftUI AsyncImage - try again on image loading failure - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744005884a2574690.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
.id
on theAsyncImage
with a value that can be changed/incremented on failure. You would obviously only want to do this a limited number of times, perhaps with a very short wait between retries. – Benzy Neez Commented Mar 29 at 20:23