SwiftUI中如何在保存至CoreData Binary Data前压缩图片尺寸?
问题描述
我有一个CoreData实体“GameSession”,其属性“photo”类型为“Binary Data”(已勾选“允许外部存储”)。目前在视图中通过PhotosPicker选择图片并保存到该属性,代码如下:
PhotosPicker(selection: $selectedItem ,matching: .images) { Label("Select a photo", systemImage: "photo") } .onChange(of: selectedItem) { newItem in Task { if let data = try? await newItem?.loadTransferable(type: Data.self) { selectedPhotoData = data } } }
保存至CoreData的代码如下:
let newSession = GameSession(context: self.moc) newSession.date = self.date newSession.setValue(self.selectedPhotoData, forKeyPath: "photo") self.moc.save()
目前功能正常,但我担心大量“session”(即大量图片)会引发内存问题。此外,我的应用仅在300×300像素的小方块中显示图片,无需存储高分辨率版本。
核心疑问:如何在保存前缩小图片尺寸?
我猜测需要对PhotosPicker中的“selectedItem”或“newItem”应用“缩小尺寸”函数,但不知具体实现方法。我知道可以使用UIImageJPEGRepresentation设置压缩比例,但不知道如何将其应用到$selectedItem上。
解决方案
你可以在将图片数据存入CoreData前,先把图片缩放到目标尺寸(300×300),再转换成压缩后的Data。具体步骤如下:
- 添加图片缩放工具函数
先写一个专门处理图片缩放的函数,传入原始UIImage和目标尺寸,返回缩放后的UIImage:
func resizeImage(_ image: UIImage, targetSize: CGSize) -> UIImage? { let size = image.size let widthRatio = targetSize.width / size.width let heightRatio = targetSize.height / size.height // 取较小的比例保证图片完整显示,避免拉伸变形 let scaleRatio = min(widthRatio, heightRatio) let newSize = CGSize(width: size.width * scaleRatio, height: size.height * scaleRatio) UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0) image.draw(in: CGRect(origin: .zero, size: newSize)) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage }
- 修改图片加载与处理逻辑
在onChange回调中,先把加载到的Data转换成UIImage,再调用缩放函数处理,最后转换成压缩后的Data:
.onChange(of: selectedItem) { newItem in Task { guard let data = try? await newItem?.loadTransferable(type: Data.self), let originalImage = UIImage(data: data) else { selectedPhotoData = nil return } // 缩放到目标尺寸300×300 let targetSize = CGSize(width: 300, height: 300) guard let resizedImage = resizeImage(originalImage, targetSize: targetSize) else { selectedPhotoData = nil return } // 转换成JPEG格式,压缩比例可自行调整(范围0.0-1.0,值越小压缩率越高) selectedPhotoData = resizedImage.jpegData(compressionQuality: 0.8) } }
- 保存逻辑无需修改
原来的CoreData保存代码可以直接复用,因为selectedPhotoData已经是处理后的压缩小图数据了。
额外优化建议
- 处理完图片后可以手动将原始UIImage实例置为nil,减少内存占用
- JPEG压缩质量设为0.8在画质和文件大小之间比较均衡,可根据实际需求调整
- 如果需要保留透明通道,也可以用
resizedImage.pngData(),但JPEG的压缩率更高,更适合节省存储空间
内容的提问来源于stack exchange,提问作者user20587286
相关产品推荐
相关产品推荐

