SwiftUI如何将选中图片保存到CoreData并在其他视图读取展示
实现方案
1. 选中图片后本地存储逻辑
我们优先把头像存储到沙盒Documents目录,相比存UserDefaults性能更好,也适合存储图片这类二进制数据。首先新增图片管理工具类:
import UIKit class ProfileImageManager { static let shared = ProfileImageManager() private let saveFileName = "user_profile_image.jpg" // 保存头像到本地 @discardableResult func saveProfileImage(_ image: UIImage) -> Bool { // 转成JPG格式,压缩质量0.8兼顾清晰度和体积 guard let imageData = image.jpegData(compressionQuality: 0.8), let docPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return false } let saveUrl = docPath.appendingPathComponent(saveFileName) do { try imageData.write(to: saveUrl) return true } catch { print("头像保存失败:\(error.localizedDescription)") return false } } // 读取本地存储的头像 func loadProfileImage() -> UIImage? { guard let docPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil } let saveUrl = docPath.appendingPathComponent(saveFileName) do { let imageData = try Data(contentsOf: saveUrl) return UIImage(data: imageData) } catch { print("头像读取失败:\(error.localizedDescription)") return nil } } }
接下来修改你现有代码,监听图片选择完成自动触发保存:
image! .resizable() .aspectRatio(contentMode: .fill) .frame(width: 150, height: 150) .clipShape(Circle()) .overlay(Circle().stroke(Color.white, lineWidth: 4)) .shadow(radius: 10) .onTapGesture { self.shouldPresentActionScheet = true } .sheet(isPresented: $shouldPresentImagePicker) { SUImagePickerView(sourceType: self.shouldPresentCamera ? .camera : .photoLibrary, image: self.$image, isPresented: self.$shouldPresentImagePicker) } .actionSheet(isPresented: $shouldPresentActionScheet) { () -> ActionSheet in ActionSheet(title: Text("选择方式"), message: Text("请选择上传头像的方式"), buttons: [ ActionSheet.Button.default(Text("相机"), action: { self.shouldPresentImagePicker = true self.shouldPresentCamera = true }), ActionSheet.Button.default(Text("相册"), action: { self.shouldPresentImagePicker = true self.shouldPresentCamera = false }), ActionSheet.Button.cancel() ]) } // 新增:监听图片变化自动保存 .onChange(of: image) { newImage in guard let validImage = newImage else { return } let saveResult = ProfileImageManager.shared.saveProfileImage(validImage) if saveResult { // 可在此处添加保存成功的toast提示 } }
2. 其他视图读取展示头像
直接调用工具类的读取方法即可,示例代码如下:
struct ProfileDisplayView: View { @State private var userAvatar: UIImage? = ProfileImageManager.shared.loadProfileImage() var body: some View { VStack { if let avatar = userAvatar { Image(uiImage: avatar) .resizable() .aspectRatio(contentMode: .fill) .frame(width: 80, height: 80) .clipShape(Circle()) } else { // 无头像时显示占位图 Image(systemName: "person.circle.fill") .resizable() .aspectRatio(contentMode: .fill) .frame(width: 80, height: 80) .foregroundColor(.gray) } } // 每次进入页面刷新头像,保证显示最新版本 .onAppear { userAvatar = ProfileImageManager.shared.loadProfileImage() } } }
注意事项
- 不需要存到系统相册,上述本地存储方式仅对当前App可见,卸载App时会同步删除
- 如果需要头像更新后所有关联页面自动刷新,可以结合NotificationCenter发通知,不需要每个页面单独处理
- 压缩质量参数可根据需求调整,范围0~1,数值越大图片越清晰、体积越大
内容的提问来源于stack exchange,提问作者Raw Bit Rabbit
相关产品推荐
相关产品推荐

