SwiftUI 列表内存问题,图像未从 RAM 中释放导致崩溃
SwiftUI List memory issue, images not deallocating from RAM causing crash
我正在将图像加载到 SwiftUI 列表中。当向下滚动太多图像时,RAM 会飙升并导致应用程序崩溃。为什么当用户向下滚动时图像没有被释放?
我正在加载图像:
List(allProducts, id: \.self) { product in
Image(uiImage: UIImage(data: dataFromRealmDB[product]))
}
我的直觉告诉我必须有一些东西可以从内存中手动释放它,所以我正在尝试以下操作。如果你如何填空,请告诉我。
List(allProducts, id: \.self) { product in
Image(uiImage: UIImage(data: dataFromRealmDB[product])).onDisappear(perform: {
"WHAT SHOULD GO HERE TO MAKE THE IMAGE GET PURGED FROM RAM?"
}
}
如果我建议的解决方案不可行,请告诉我。
更新
我改变了图像的存储方式。现在它们存储在 FileManager 中,而不是将它们保存到 RealmDB 中。这是我获取图像的功能。仍然内存使用增加导致崩溃,没有从 SwiftUI 释放。
func getImage(link: String) -> Image? {
let lastPath = URL(string: link)?.lastPathComponent
if let dir = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
let image : UIImage? = UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(lastPath!).path)
if image != nil {
return Image(uiImage: UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(lastPath!).path)!)
}
}
return Image("noImg")
}
您确定这与您从数据库中获取图像原始数据无关吗?根据这个问题 就像一个 tableview - 即重用单元格。
我认为您使用数据库来保存图像的原始数据这一事实会导致内存激增。
这是一种基于意见的答案,但我建议要么在应用程序中提前捆绑图像(如果您的业务逻辑支持),要么在数据库中使用名称并按名称初始化它们。
或者远程托管它们并按需获取。
问题中的代码有点不完整,但答案确实不是编码答案,更像是整体设计答案。
Realm 对象是延迟加载的,如果使用得当,基本上不会溢出内存;它们仅在使用时存储在内存中;例如一个包含 10,000 个对象的 Realm Results 对象很容易处理,内存会自动分配和释放。
关于这一点,如果您将 Realm 对象存储在其他 non-Realm 对象(如数组)中,这将完全改变内存影响并可能使设备不堪重负。
但是,更重要的是:
Realm 不是存储 Blob 数据(全尺寸图片)的好方法。一个领域 属性 的 storage of 16Mb 数量是有限的,而图像很容易超出这个范围。
MongoDB 和 Firebase 还有其他图片存储选项。
有关详细信息,请参阅我对 的回答
最后,您应该使用分页来控制一次从您使用的任何来源加载多少张图片;这将使您可以更轻松地控制内存分配和 UI.
因此最后一部分很重要,无论采用何种技术,将一堆图像加载到内存中最终都会使设备不堪重负,因此您可以看到,转而使用 FileManger 从磁盘加载图像Realm 不会是一个长期的解决方案;分页是要走的路。
有一些第三方库可以帮助您 and/or 您可以制作自己的库。在 SO 上搜索 'image pagination',因为它讨论了 lot
哦 - 还有一件事;请为您的 UI 使用缩略图!如果用户点击或选择它,您只需要真正显示全尺寸图像 - 然后您可以从磁盘加载它。 Firebase Storage 实际上可以为您做到这一点;当您上传全尺寸图片时,它可以(在他们的服务器上)为您的 UI.
创建缩略图
同样,缩略图很小,Realm 可以轻松处理;设计将是这样的对象
class MyImageObject: Object {
@Persisted var imageURL: //a string or url to where it's stored on disk
@Persisted var thumbnail: Data!
@Persisted var image_name = "" //the image name
}
我正在将图像加载到 SwiftUI 列表中。当向下滚动太多图像时,RAM 会飙升并导致应用程序崩溃。为什么当用户向下滚动时图像没有被释放?
我正在加载图像:
List(allProducts, id: \.self) { product in
Image(uiImage: UIImage(data: dataFromRealmDB[product]))
}
我的直觉告诉我必须有一些东西可以从内存中手动释放它,所以我正在尝试以下操作。如果你如何填空,请告诉我。
List(allProducts, id: \.self) { product in
Image(uiImage: UIImage(data: dataFromRealmDB[product])).onDisappear(perform: {
"WHAT SHOULD GO HERE TO MAKE THE IMAGE GET PURGED FROM RAM?"
}
}
如果我建议的解决方案不可行,请告诉我。
更新
我改变了图像的存储方式。现在它们存储在 FileManager 中,而不是将它们保存到 RealmDB 中。这是我获取图像的功能。仍然内存使用增加导致崩溃,没有从 SwiftUI 释放。
func getImage(link: String) -> Image? {
let lastPath = URL(string: link)?.lastPathComponent
if let dir = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
let image : UIImage? = UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(lastPath!).path)
if image != nil {
return Image(uiImage: UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(lastPath!).path)!)
}
}
return Image("noImg")
}
您确定这与您从数据库中获取图像原始数据无关吗?根据这个问题
我认为您使用数据库来保存图像的原始数据这一事实会导致内存激增。
这是一种基于意见的答案,但我建议要么在应用程序中提前捆绑图像(如果您的业务逻辑支持),要么在数据库中使用名称并按名称初始化它们。
或者远程托管它们并按需获取。
问题中的代码有点不完整,但答案确实不是编码答案,更像是整体设计答案。
Realm 对象是延迟加载的,如果使用得当,基本上不会溢出内存;它们仅在使用时存储在内存中;例如一个包含 10,000 个对象的 Realm Results 对象很容易处理,内存会自动分配和释放。
关于这一点,如果您将 Realm 对象存储在其他 non-Realm 对象(如数组)中,这将完全改变内存影响并可能使设备不堪重负。
但是,更重要的是:
Realm 不是存储 Blob 数据(全尺寸图片)的好方法。一个领域 属性 的 storage of 16Mb 数量是有限的,而图像很容易超出这个范围。
MongoDB 和 Firebase 还有其他图片存储选项。
有关详细信息,请参阅我对
最后,您应该使用分页来控制一次从您使用的任何来源加载多少张图片;这将使您可以更轻松地控制内存分配和 UI.
因此最后一部分很重要,无论采用何种技术,将一堆图像加载到内存中最终都会使设备不堪重负,因此您可以看到,转而使用 FileManger 从磁盘加载图像Realm 不会是一个长期的解决方案;分页是要走的路。
有一些第三方库可以帮助您 and/or 您可以制作自己的库。在 SO 上搜索 'image pagination',因为它讨论了 lot
哦 - 还有一件事;请为您的 UI 使用缩略图!如果用户点击或选择它,您只需要真正显示全尺寸图像 - 然后您可以从磁盘加载它。 Firebase Storage 实际上可以为您做到这一点;当您上传全尺寸图片时,它可以(在他们的服务器上)为您的 UI.
创建缩略图同样,缩略图很小,Realm 可以轻松处理;设计将是这样的对象
class MyImageObject: Object {
@Persisted var imageURL: //a string or url to where it's stored on disk
@Persisted var thumbnail: Data!
@Persisted var image_name = "" //the image name
}