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

Swift/SwiftUI iOS迭代写入多张图片到Documents文件夹内存溢出问题咨询

问题原因分析
  • 核心原因是批量处理图片过程中产生的UIImage、JPEG数据流等临时对象都堆积在自动释放池中,要等整个循环执行完成后才会统一释放,几千张图片的临时资源累积直接导致内存占用飙升,最终触发分配失败。
  • 你当前使用的全量加载原图再缩放的逻辑会额外占用大量内存,单张4000*3000的原图解压后就占接近48MB内存,多几张就会把内存吃满。
  • JPEG写入时设置的压缩质量为1.0,生成的文件数据体积过大,进一步加剧内存占用。
可行解决方案

1. 循环内添加自动释放池即时释放临时资源

在最内层的单张图片处理逻辑外层包裹@autoreleasepool,每处理完一张图片就直接释放对应的临时对象,从根源解决内存累积问题,修改后的genThumbnails逻辑如下:

func genThumbnails() -> Void {
    // 放到后台队列处理,避免卡住主线程
    DispatchQueue.global(qos: .utility).async { [weak self] in
        guard let self = self else { return }
        for ind in self.foldersData.subDirNames.indices {
            for indd in self.foldersData.galContents[ind].indices {
                // 单张图片处理逻辑全放进自动释放池
                @autoreleasepool {
                    let imgPath = self.foldersData.galContents[ind][indd]
                    let dirPath: String
                    if self.foldersData.subDirNames[ind] == "Root Folder" {
                        dirPath = NSHomeDirectory().appending("/Documents/Thumbnails/")
                    } else {
                        dirPath = NSHomeDirectory().appending("/Documents/Thumbnails/" + self.foldersData.subDirNames[ind])
                    }
                    // 优先用优化后的缩略图生成方法,不要先加载全图
                    if let thumbnail = self.generateThumbnail(path: imgPath, maxSize: max(FoldersViewModel.imageSize[0]/4, FoldersViewModel.imageSize[1]/4)) {
                        _ = self.foldersData.genThumbnailFiles(thumbnail, filename: (imgPath as NSString).lastPathComponent, directoryPath: dirPath)
                    }
                    self.counts[0] = self.counts[0] + 1
                }
            }
            self.counts[1] = self.counts[1] + 1
        }
        DispatchQueue.main.async {
            self.foldersData.isLoading = false
        }
    }
}

2. 用ImageIO优化缩略图生成逻辑

不加载全量原图,直接从文件读取时生成指定尺寸的缩略图,内存占用可以降低90%以上,示例代码:

func generateThumbnail(path: String, maxSize: CGFloat) -> UIImage? {
    guard let url = URL(fileURLWithPath: path) as CFURL?,
          let imageSource = CGImageSourceCreateWithURL(url, nil) else {
        return nil
    }
    let options: [CFString: Any] = [
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceThumbnailMaxPixelSize: maxSize,
        kCGImageSourceCreateThumbnailWithTransform: true
    ]
    guard let cgThumbnail = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) else {
        return nil
    }
    return UIImage(cgImage: cgThumbnail)
}

3. 调整JPEG压缩参数

将jpegData(compressionQuality: 1.0)改为compressionQuality: 0.7,肉眼几乎看不出画质差异,但生成的文件体积可以减少70%左右,写入时的内存占用也会大幅降低。

4. 优化数据存储逻辑

不要在galContents数组中存储全量UIImage对象,仅存储图片的本地文件路径,需要用到的时候再读取,避免不必要的内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 13:24:00