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

为什么从Realm DB加载图片到SwiftUI List时会崩溃且RAM达到上限?

内存不释放的核心原因

你遇到的问题本质和SwiftUI List的复用机制无关,是代码逻辑导致图片实例被持续持有无法释放:

  1. 你提前把所有转换好的Image实例存入了全局的imageList数组,这个数组会强持有所有Image对应的UIImage对象,就算List单元格滚出屏幕被复用,数组里的图片实例依然存在,内存自然不会下降
  2. 你直接将全尺寸的Data转换为UIImage使用,没有做降采样,单张图片的内存占用极高(比如一张1080P的图片内存占用就有~8MB,7000张全加载的话要远超过手机可用内存)
  3. List内嵌套横向ScrollView时,你用普通HStack加载所有横向图片,相当于每个List行都会一次性加载该行所有图片,没有懒加载机制,进一步加快了内存上涨速度

解决思路

  • 摒弃预生成全局imageList的写法,改为按需加载:只在ForEach渲染单个图片的时候,实时从Realm读取对应Data、生成图片,不要全局持有所有图片实例,滚出可视区的单元格销毁后,对应的图片没有被强持有就会自动释放
  • 强制做图片降采样,不要直接使用全尺寸UIImage,根据列表图片的实际显示尺寸生成对应大小的缩略图,内存占用可以降低90%以上,示例实现:
func downsampleImage(from data: Data, targetSize: CGSize) -> UIImage? {
    let scale = UIScreen.main.scale
    let maxPixel = max(targetSize.width, targetSize.height) * scale
    let options: [CFString: Any] = [
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceThumbnailMaxPixelSize: maxPixel,
        kCGImageSourceCreateThumbnailWithTransform: true
    ]
    guard let source = CGImageSourceCreateWithData(data as CFData, nil),
          let cgThumbnail = CGImageSourceCreateThumbnailAtIndex(source, 0, options as CFDictionary) else {
        return nil
    }
    return UIImage(cgImage: cgThumbnail)
}
  • 把横向ScrollView里的HStack替换为LazyHStack,让横向滚动的图片也支持懒加载,避免每行一次性加载全部横向图片
  • 修正ForEach的标识逻辑,不要用数组下标作为id,改为使用图片在Realm中存储的唯一主键作为id,保证List的单元格复用逻辑正常生效
  • 可选添加内存缓存优化:用NSCache存储降采样后的UIImage,设置合理的缓存上限(比如总内存限制100M、最多缓存200张图),NSCache会在系统内存紧张时自动释放缓存内容,既可以提升滚动流畅度,也不会出现内存溢出问题
  • 尽量固定List的行高,避免动态高度导致List复用逻辑失效,iOS 16及以上版本可以配合listRowSeparator(.visible)等Modifier明确List的布局规则,提升复用效率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 18:15:04