You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 23:01:09