LazyVStack滚动时内存未释放的问题解决咨询
你遇到的这个情况我太熟悉了——LazyVStack理论上会自动回收不可见视图的内存,但实际没生效,大概率是图片加载后没被正确释放,或者视图持有了不必要的引用。下面给你几个针对性的解决思路:
用SwiftUI原生组件自动处理内存
如果你现在是手动用UIImage加载本地图片,建议换成iOS 15+提供的AsyncImage来加载本地文件路径的图片,它内部会自动处理内存的缓存和释放逻辑,不用你手动管理:AsyncImage(url: URL(fileURLWithPath: imagePathFromCoreData)) { phase in switch phase { case .success(let image): image.resizable() .scaledToFit() case .failure: Image(systemName: "photo.badge.exclamationmark") // 错误占位图 case .empty: ProgressView() // 加载占位图 @unknown default: EmptyView() } }要是你必须自定义加载逻辑,记得在视图的
onDisappear回调里把持有的UIImage实例置为nil,让SwiftUI的视图生命周期能及时回收内存。避免强持有全部CoreData数据
如果你是把CoreData查询到的所有图片路径都存在ViewModel的数组里,会导致所有数据被强持有,连带图片资源也无法释放。建议直接在View中用@FetchRequest绑定数据,让SwiftUI只管理当前可见的对象:@FetchRequest(sortDescriptors: [SortDescriptor(\.saveDate, order: .reverse)]) private var storedImages: FetchedResults<ImageEntity> var body: some View { ScrollView { LazyVStack(spacing: 16) { ForEach(storedImages) { imageEntity in // 这里放你的图片显示视图 } } .padding() } }优化图片加载的内存占用
很多时候内存增长快不是因为没释放,而是单张图片占用内存太大。加载图片时记得缩放到显示所需的尺寸,不要直接加载原始大图:func loadScaledImage(from path: String, targetSize: CGSize) -> UIImage? { guard let image = UIImage(contentsOfFile: path) else { return nil } let renderer = UIGraphicsImageRenderer(size: targetSize) return renderer.image { context in image.draw(in: CGRect(origin: .zero, size: targetSize)) } }另外如果用了自定义内存缓存,一定要设置缓存上限,并且监听系统的内存警告通知,及时清理缓存:
init() { NotificationCenter.default.addObserver( forName: UIApplication.didReceiveMemoryWarningNotification, object: nil, queue: .main ) { [weak self] _ in self?.imageCache.removeAllObjects() } }检查视图的引用链是否有循环
看看你的图片视图里有没有闭包、回调或者其他对象持有了强引用,导致视图无法被销毁。比如在onAppear或自定义的加载方法里,要用[weak self]捕获引用:.onAppear { [weak self] in guard let self = self else { return } self.loadImage(for: imageEntity.filePath) }要是你封装了自定义的ImageLoader类,确保它是用
@ObservedObject或@StateObject管理,不会产生循环引用。
备注:内容来源于stack exchange,提问作者Олександр Романюк

