You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI多个AsyncImage组件意外相互影响,请求排查异常原因

问题描述

点击按钮后触发三个异步任务获取图片URL,分别传给三个AsyncImage组件,但只要有一张图片加载完成,另外两个的ProgressView就会消失,直接显示初始占位图。

相关代码

按钮点击逻辑

LargeButton(title: "Generate",
            disabled: isFetchingImage,
            backgroundColor: Color.blue,
            foregroundColor: Color.white) {
    focusedField = nil
    Task {
        fetching1 = true
        let getURL = try await networkFetch1()
        fetching1 = false
        imageURL1 = getURL ?? ""
    }
    Task {
        fetching2 = true
        let getURL = try await networkFetch2()
        fetching2 = false
        imageURL2 = getURL ?? ""
    }
    Task {
        fetching3 = true
        let getURL = try await networkFetch3()
        fetching3 = false
        imageURL3 = getURL ?? ""
    }
}

AsyncImage组件

AsyncImage(url: URL(string: imageURL)) { phase in
    if fetching {
        ProgressView()
    } else if let image = phase.image {
        image
            .resizable()
            .scaledToFit()
    } else if phase.error != nil {
        Text("There was an error loading the image.")
    } else {
        Image("SMPTE_Color_Bars.svg")
            .resizable()
            .scaledToFit()
    }
}       

状态变量

@State private var fetching1: Bool = false
@State private var fetching2: Bool = false
@State private var fetching3: Bool = false

@State private var imageURL1: String = ""
@State private var imageURL2: String = ""
@State private var imageURL3: String = ""

问题现象

点击按钮后三个AsyncImage都显示ProgressView,但任意一张图片加载完成后,另外两个的ProgressView会消失,直接显示初始占位图(SMPTE_Color_Bars.svg)。


问题原因与解决方案

原因分析

  1. 状态变量复用错误:每个AsyncImage的加载状态判断,应该对应各自的fetching1/fetching2/fetching3,但你当前的代码里统一用了fetching变量(推测是复用了同一个状态,比如三个AsyncImage都用了fetching1)。当某一个fetchingX被设为false后,其他复用该变量的AsyncImage会直接退出ProgressView分支,跳到初始占位图逻辑。
  2. 自定义状态与AsyncImage原生状态冲突:AsyncImage本身通过phase参数提供了完整的加载状态(空、成功、失败),额外维护fetchingX变量属于冗余操作,反而会打乱组件的原生状态逻辑。

解决方案

核心修改:移除自定义fetching变量,复用AsyncImage原生状态

删除所有fetching1/fetching2/fetching3状态变量,直接通过AsyncImage的phase判断加载状态,同时确保每个AsyncImage绑定对应独立的imageURL:

修改后的单个AsyncImage示例(对应第一个图片):

AsyncImage(url: URL(string: imageURL1)) { phase in
    switch phase {
    case .empty:
        // 未开始加载或正在加载时显示进度条
        ProgressView()
    case .success(let image):
        image
            .resizable()
            .scaledToFit()
    case .failure(_):
        Text("加载图片出错")
    @unknown default:
        Image("SMPTE_Color_Bars.svg")
            .resizable()
            .scaledToFit()
    }
}

按钮逻辑优化(可选)

把三个异步请求合并到同一个Task里,用并发语法简化代码:

LargeButton(title: "Generate",
            disabled: isFetchingImage,
            backgroundColor: Color.blue,
            foregroundColor: Color.white) {
    focusedField = nil
    Task {
        async let url1 = networkFetch1()
        async let url2 = networkFetch2()
        async let url3 = networkFetch3()
        
        do {
            let (result1, result2, result3) = try await (url1, url2, url3)
            imageURL1 = result1 ?? ""
            imageURL2 = result2 ?? ""
            imageURL3 = result3 ?? ""
        } catch {
            // 统一处理请求错误
        }
    }
}

修改后,每个AsyncImage会独立根据自身的加载状态显示对应内容,不会出现一个图片加载完成影响其他组件的问题。

内容的提问来源于stack exchange,提问作者erotsppa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 15:19:31