如何通过iOS 16 Photos Picker(SwiftUI)获取图片路径并存储至JSON?
从iOS 16 Photos Picker获取可存储的图片路径并用于后续展示
核心说明
iOS的Photos框架出于隐私保护,不会直接提供系统相册图片的绝对路径给App。正确的做法是:将选中的图片复制到App的沙箱目录(比如Documents或Caches),然后存储这个沙箱内的路径到JSON,后续通过该路径读取本地文件展示。
实现步骤
1. 配置Photos Picker并获取选中图片
使用PHPickerViewController选择图片,提取图片数据后保存到沙箱:
import PhotosUI import SwiftUI struct PhotoPickerView: UIViewControllerRepresentable { @Binding var selectedImagePath: String? func makeUIViewController(context: Context) -> PHPickerViewController { var configuration = PHPickerConfiguration() configuration.filter = .images configuration.selectionLimit = 1 let picker = PHPickerViewController(configuration: configuration) picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, PHPickerViewControllerDelegate { let parent: PhotoPickerView init(_ parent: PhotoPickerView) { self.parent = parent } func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true) guard let result = results.first else { return } if result.itemProvider.canLoadObject(ofClass: UIImage.self) { result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in guard let uiImage = image as? UIImage, error == nil else { return } self?.saveImageToSandbox(uiImage) } } } private func saveImageToSandbox(_ image: UIImage) { guard let imageData = image.jpegData(compressionQuality: 0.8) else { return } // 获取Documents目录 let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! // 生成唯一文件名避免重复 let fileName = UUID().uuidString + ".jpeg" let fileURL = documentsDir.appendingPathComponent(fileName) do { try imageData.write(to: fileURL) // 存储相对路径(避免App重装后绝对路径变化) let relativePath = fileURL.path.replacingOccurrences(of: documentsDir.path, with: "") DispatchQueue.main.async { self.parent.selectedImagePath = relativePath } } catch { print("保存图片失败:\(error.localizedDescription)") } } } }
2. 将路径存入JSON文件
创建可编码的数据模型,将路径写入JSON:
struct ImageRecord: Codable { var imageRelativePath: String? } // 保存路径到JSON的方法 func savePathToJSON(path: String) { let record = ImageRecord(imageRelativePath: path) let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted guard let jsonData = try? encoder.encode(record) else { return } let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let jsonURL = documentsDir.appendingPathComponent("imageRecords.json") do { try jsonData.write(to: jsonURL) } catch { print("写入JSON失败:\(error.localizedDescription)") } }
3. 从JSON读取路径并展示图片
读取JSON中的相对路径,拼接成完整沙箱URL后加载图片:
// 读取JSON路径的方法 func loadPathFromJSON() -> String? { let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let jsonURL = documentsDir.appendingPathComponent("imageRecords.json") guard let jsonData = try? Data(contentsOf: jsonURL) else { return nil } let decoder = JSONDecoder() guard let record = try? decoder.decode(ImageRecord.self, from: jsonData) else { return nil } return record.imageRelativePath } // SwiftUI展示视图 struct ImageDisplayView: View { @State private var displayImage: UIImage? var body: some View { displayImage.map { Image(uiImage: $0) } .resizable() .scaledToFit() .onAppear { loadDisplayImage() } } private func loadDisplayImage() { guard let relativePath = loadPathFromJSON() else { return } let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let fileURL = documentsDir.appendingPathComponent(relativePath) if let imageData = try? Data(contentsOf: fileURL) { displayImage = UIImage(data: imageData) } } }
关键注意事项
- 不要尝试存储系统相册的绝对路径:iOS沙箱限制App直接访问系统相册路径,且该路径不具备持久性,App重装或系统更新后会失效。
- 使用UUID命名文件:避免重复文件名导致图片被覆盖。
- 如需存储多张图片,可将
ImageRecord修改为包含路径数组的模型,比如struct ImageRecords: Codable { var paths: [String] }。
内容的提问来源于stack exchange,提问作者Tyrel Smith
相关产品推荐
相关产品推荐

