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

SwiftUI中Image相关内存泄漏警告问题求助

内存泄漏分析与解决方法

问题原因

你的代码中内存泄漏的核心诱因是Model类里photosPickerItem的didSet中启动的异步Task——该Task会隐式捕获Model实例的引用。当用户点击Clear按钮清空imageData,或者多次切换选择照片时,未完成的旧Task仍会持有Model实例,导致其无法被系统回收,进而触发内存泄漏警告。

另外原代码存在两处冗余/风险点:

  • 逐个判断图片类型属于冗余操作,UTType.image是所有图片格式的父类型,可覆盖你列出的所有格式;
  • ContentView中使用强制解包!,存在运行时崩溃风险。

修复后的代码

Model类优化(处理Task生命周期)

@MainActor
class Model: ObservableObject{
    @Published var photosPickerItem: PhotosPickerItem? {
        didSet{
            // 取消未完成的旧任务,避免持有无效引用
            loadTask?.cancel()
            guard let photosPickerItem = photosPickerItem else {
                return
            }
            // 保存新任务引用,便于后续管理
            loadTask = Task{
                do {
                    try await loadTransferrable(from: photosPickerItem)
                } catch is CancellationError {
                    // 任务被取消属于预期情况,无需额外处理
                } catch {
                    print("图片加载失败:\(error.localizedDescription)")
                }
            }
        }
    }
    @Published var imageData: Data?
    // 持有加载任务的引用,用于取消操作
    private var loadTask: Task<Void, Error>?
    
    func loadTransferrable(from item: PhotosPickerItem) async throws{
        // 简化类型检查,UTType.image覆盖所有支持的图片格式
        guard item.supportedContentTypes.contains(.image) else {
            return
        }
        if let data = try await item.loadTransferable(type: Data.self){
            imageData = data
        }
    }
    
    func clearImage(){
        imageData = nil
        // 可选:若需要立即终止未完成的加载任务,可取消
        // loadTask?.cancel()
    }
    
    // 实例销毁时自动取消任务,彻底释放资源
    deinit {
        loadTask?.cancel()
    }
}

ContentView优化(移除强制解包)

struct ContentView: View {
    @State var isShowingPicker = false
    @StateObject var model = Model()
    var body: some View {
        ZStack {
            // 安全解包,避免强制解包导致的崩溃
            if let imageData = model.imageData, let uiImage = UIImage(data: imageData) {
                Image(uiImage: uiImage)
                    .resizable()
                    .scaledToFit()
            }
            HStack{
                Button("Picker Button") {
                    isShowingPicker.toggle()
                }
                
                Button("Clear Button") {
                    model.clearImage()
                }
            }
        }
        .photosPicker(isPresented: $isShowingPicker, selection: $model.photosPickerItem)
    }
}

修复说明

  1. Task生命周期管理:通过loadTask引用跟踪异步任务,在photosPickerItem更新时取消旧任务,在Model实例销毁时自动取消剩余任务,打破Task对Model的持有引用,确保实例能被正常回收。
  2. 简化类型检查:利用UTType.image的父类型特性,减少冗余代码,同时覆盖所有图片格式。
  3. 安全解包:替换强制解包为可选绑定,避免因数据异常导致的运行时崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:07:42