技术 · 2025年3月15日 0

使用SwiftUI从相册选择照片并显示

使用SwiftUI从相册选择照片并显示,可以使用PHPickerViewController,它是iOS 14及更高版本中推荐的照片选择器。以下是一个基本示例,演示如何从相册中选择照片并在SwiftUI视图中显示:

  1. 首先,确保在项目中导入必要的库:
import SwiftUI
import PhotosUI
  1. 创建一个结构体来管理照片选择器的配置和结果:
struct PhotoPicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        var parent: PhotoPicker

        init(parent: PhotoPicker) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            guard let provider = results.first?.itemProvider else { return }

            if provider.canLoadObject(ofClass: UIImage.self) {
                provider.loadObject(ofClass: UIImage.self) { (image, error) in
                    DispatchQueue.main.async {
                        self.parent.image = image as? UIImage
                    }
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeUIViewController(context: Context) -> PHPickerViewController {
        var configuration = PHPickerConfiguration()
        configuration.filter = .images
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}
}
  1. 创建一个SwiftUI视图来显示选中的图片并触发照片选择器:
struct ContentView: View {
    @State private var image: UIImage?
    @State private var isPickerPresented = false

    var body: some View {
        VStack {
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300, height: 300)
            } else {
                Text("选择一张照片")
                    .foregroundColor(.gray)
                    .frame(width: 300, height: 300)
                    .background(Color.gray.opacity(0.1))
            }

            Button(action: {
                isPickerPresented.toggle()
            }) {
                Text("从相册选择照片")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
        .sheet(isPresented: $isPickerPresented) {
            PhotoPicker(image: $image)
        }
    }
}
  1. 最后,在@main应用程序结构体中引用ContentView
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

这个示例展示了如何使用PHPickerViewController从相册中选择一张照片,并在SwiftUI视图中显示选中的照片。你可以根据需要扩展这个基础示例来满足你的具体需求。

修改这段代码支持从相册加载照片:

// 获取RAW图像的URL
guard let fileURL = Bundle.main.url(forResource: “照片名称”, withExtension: “照片扩展名”) else {
print(“未找到文件”)
return
}

要从相册中选择照片并获取RAW图像的URL,你需要修改代码以适应处理RAW图像。PHPickerViewController在iOS 14及更高版本中可以选择RAW图像。以下是如何修改代码以支持从相册中选择RAW图像并获取其URL:

  1. 确保在项目中导入必要的库:
import SwiftUI
import PhotosUI
  1. 创建一个结构体来管理照片选择器的配置和结果:
struct PhotoPicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Binding var imageURL: URL?

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        var parent: PhotoPicker

        init(parent: PhotoPicker) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            guard let provider = results.first?.itemProvider else { return }

            if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
                    DispatchQueue.main.async {
                        if let url = url {
                            self.parent.imageURL = url
                            do {
                                let data = try Data(contentsOf: url)
                                self.parent.image = UIImage(data: data)
                            } catch {
                                print("Error loading image data: \(error)")
                            }
                        }
                    }
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    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) {}
}
  1. 创建一个SwiftUI视图来显示选中的图片并触发照片选择器:
struct ContentView: View {
    @State private var image: UIImage?
    @State private var imageURL: URL?
    @State private var isPickerPresented = false

    var body: some View {
        VStack {
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300, height: 300)
            } else {
                Text("选择一张照片")
                    .foregroundColor(.gray)
                    .frame(width: 300, height: 300)
                    .background(Color.gray.opacity(0.1))
            }

            Button(action: {
                isPickerPresented.toggle()
            }) {
                Text("从相册选择照片")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }

            if let imageURL = imageURL {
                Text("图像URL: \(imageURL.absoluteString)")
                    .padding()
                    .foregroundColor(.gray)
            }
        }
        .sheet(isPresented: $isPickerPresented) {
            PhotoPicker(image: $image, imageURL: $imageURL)
        }
    }
}
  1. @main应用程序结构体中引用ContentView
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

这个示例展示了如何使用PHPickerViewController从相册中选择一张照片并获取其URL。选中的照片会显示在SwiftUI视图中,同时显示其URL。你可以根据需要进一步扩展这个示例以处理更多的图像类型或提供其他功能。

出现了如下错误

Error loading image data: Error Domain=NSCocoaErrorDomain Code=260 "The file “RAW_SONY_RX10.arw” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/private/var/mobile/Containers/Data/Application/7CD03626-AF9A-4893-AABC-72C4A561D6EF/tmp/.com.apple.Foundation.NSItemProvider.iYvhms/RAW_SONY_RX10.arw, NSUnderlyingError=0x283e9a0d0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

该错误表明在尝试加载选定的RAW文件时出现问题,可能是由于文件路径问题或文件没有正确加载。为了确保能够正确处理RAW文件,我们需要检查并确保文件路径和数据处理是正确的。

以下是更新的代码示例,使用loadFileRepresentation来获取文件路径并处理RAW图像:

  1. 确保在项目中导入必要的库:
import SwiftUI
import PhotosUI
import UniformTypeIdentifiers
  1. 更新PhotoPicker结构体以正确处理RAW图像文件:
struct PhotoPicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Binding var imageURL: URL?

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        var parent: PhotoPicker

        init(parent: PhotoPicker) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            guard let provider = results.first?.itemProvider else { return }

            if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
                    if let error = error {
                        print("Error loading file representation: \(error)")
                        return
                    }
                    guard let url = url else { return }

                    do {
                        let tempDirectory = FileManager.default.temporaryDirectory
                        let targetURL = tempDirectory.appendingPathComponent(url.lastPathComponent)
                        try FileManager.default.copyItem(at: url, to: targetURL)

                        DispatchQueue.main.async {
                            self.parent.imageURL = targetURL
                            self.parent.image = UIImage(contentsOfFile: targetURL.path)
                        }
                    } catch {
                        print("Error copying file: \(error)")
                    }
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    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) {}
}
  1. 更新ContentView以显示选中的图像并触发照片选择器:
struct ContentView: View {
    @State private var image: UIImage?
    @State private var imageURL: URL?
    @State private var isPickerPresented = false

    var body: some View {
        VStack {
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300, height: 300)
            } else {
                Text("选择一张照片")
                    .foregroundColor(.gray)
                    .frame(width: 300, height: 300)
                    .background(Color.gray.opacity(0.1))
            }

            Button(action: {
                isPickerPresented.toggle()
            }) {
                Text("从相册选择照片")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }

            if let imageURL = imageURL {
                Text("图像URL: \(imageURL.absoluteString)")
                    .padding()
                    .foregroundColor(.gray)
            }
        }
        .sheet(isPresented: $isPickerPresented) {
            PhotoPicker(image: $image, imageURL: $imageURL)
        }
    }
}
  1. @main应用程序结构体中引用ContentView
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

这个更新的示例代码确保从相册中选择RAW图像并将其复制到临时目录,然后从临时目录加载图像数据以显示在SwiftUI视图中。这应该可以解决“文件不存在”的问题,并正确处理RAW图像文件。

控制台报错了

Error copying file: Error Domain=NSCocoaErrorDomain Code=516 "“RAW_SONY_RX10.arw” couldn’t be copied to “tmp” because an item with the same name already exists." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/C87AC9D6-0A2C-42B5-9785-AEA22798B28E/tmp/.com.apple.Foundation.NSItemProvider.iQeC09/RAW_SONY_RX10.arw, NSUserStringVariant=(
    Copy
), NSDestinationFilePath=/private/var/mobile/Containers/Data/Application/C87AC9D6-0A2C-42B5-9785-AEA22798B28E/tmp/RAW_SONY_RX10.arw, NSFilePath=/private/var/mobile/Containers/Data/Application/C87AC9D6-0A2C-42B5-9785-AEA22798B28E/tmp/.com.apple.Foundation.NSItemProvider.iQeC09/RAW_SONY_RX10.arw, NSUnderlyingError=0x281c38d20 {Error Domain=NSPOSIXErrorDomain Code=17 "File exists"}}

这个错误表明目标目录中已经存在同名文件。为了解决这个问题,我们可以在复制文件之前删除已存在的同名文件,或者为文件名添加一个唯一标识符。

以下是更新后的代码,确保在复制文件之前删除已存在的同名文件:

  1. 确保在项目中导入必要的库:
import SwiftUI
import PhotosUI
import UniformTypeIdentifiers
  1. 更新PhotoPicker结构体以正确处理RAW图像文件:
struct PhotoPicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Binding var imageURL: URL?

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        var parent: PhotoPicker

        init(parent: PhotoPicker) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            guard let provider = results.first?.itemProvider else { return }

            if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
                    if let error = error {
                        print("Error loading file representation: \(error)")
                        return
                    }
                    guard let url = url else { return }

                    do {
                        let tempDirectory = FileManager.default.temporaryDirectory
                        let targetURL = tempDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension(url.pathExtension)

                        if FileManager.default.fileExists(atPath: targetURL.path) {
                            try FileManager.default.removeItem(at: targetURL)
                        }
                        try FileManager.default.copyItem(at: url, to: targetURL)

                        DispatchQueue.main.async {
                            self.parent.imageURL = targetURL
                            self.parent.image = UIImage(contentsOfFile: targetURL.path)
                        }
                    } catch {
                        print("Error copying file: \(error)")
                    }
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    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) {}
}
  1. 更新ContentView以显示选中的图像并触发照片选择器:
struct ContentView: View {
    @State private var image: UIImage?
    @State private var imageURL: URL?
    @State private var isPickerPresented = false

    var body: some View {
        VStack {
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300, height: 300)
            } else {
                Text("选择一张照片")
                    .foregroundColor(.gray)
                    .frame(width: 300, height: 300)
                    .background(Color.gray.opacity(0.1))
            }

            Button(action: {
                isPickerPresented.toggle()
            }) {
                Text("从相册选择照片")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }

            if let imageURL = imageURL {
                Text("图像URL: \(imageURL.absoluteString)")
                    .padding()
                    .foregroundColor(.gray)
            }
        }
        .sheet(isPresented: $isPickerPresented) {
            PhotoPicker(image: $image, imageURL: $imageURL)
        }
    }
}
  1. @main应用程序结构体中引用ContentView
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

这个更新的示例代码确保在复制文件之前为文件名添加一个唯一标识符,以避免文件名冲突,并确保可以正确处理和加载RAW图像。这样可以避免因文件名冲突而导致的错误。

很好,这段代码能查看相册中的所有RAW格式的照片。请继续修改代码,用List展示相册中的所有照片。

要展示相册中的所有RAW格式的照片,并使用List展示在SwiftUI中,我们需要使用PHFetchResult从相册中获取所有RAW格式的照片,然后在SwiftUI视图中展示这些照片的缩略图。

以下是更新后的代码,展示如何实现这个功能:

  1. 确保在项目中导入必要的库:
import SwiftUI
import Photos
import PhotosUI
  1. 创建一个结构体来管理从相册中获取RAW照片:
struct PhotoPickerView: UIViewControllerRepresentable {
    @Binding var images: [UIImage]
    @Binding var imageURLs: [URL]

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        var parent: PhotoPickerView

        init(parent: PhotoPickerView) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            for result in results {
                let provider = result.itemProvider

                if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                    provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
                        if let error = error {
                            print("Error loading file representation: \(error)")
                            return
                        }
                        guard let url = url else { return }

                        do {
                            let tempDirectory = FileManager.default.temporaryDirectory
                            let targetURL = tempDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension(url.pathExtension)

                            if FileManager.default.fileExists(atPath: targetURL.path) {
                                try FileManager.default.removeItem(at: targetURL)
                            }
                            try FileManager.default.copyItem(at: url, to: targetURL)

                            DispatchQueue.main.async {
                                self.parent.imageURLs.append(targetURL)
                                if let image = UIImage(contentsOfFile: targetURL.path) {
                                    self.parent.images.append(image)
                                }
                            }
                        } catch {
                            print("Error copying file: \(error)")
                        }
                    }
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeUIViewController(context: Context) -> PHPickerViewController {
        var configuration = PHPickerConfiguration()
        configuration.filter = .images
        configuration.selectionLimit = 0
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}
}
  1. 创建一个视图模型来管理照片数据:
class PhotoLibraryViewModel: ObservableObject {
    @Published var images: [UIImage] = []
    @Published var imageURLs: [URL] = []

    func loadRawPhotos() {
        let fetchOptions = PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "mediaType == %d", PHAssetMediaType.image.rawValue)

        let allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)

        allPhotos.enumerateObjects { (asset, _, _) in
            let options = PHImageRequestOptions()
            options.isSynchronous = true
            PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: options) { (image, info) in
                if let image = image {
                    DispatchQueue.main.async {
                        self.images.append(image)
                    }
                }
            }

            PHImageManager.default().requestImageData(for: asset, options: options) { (data, _, _, info) in
                if let url = info?["PHImageFileURLKey"] as? URL {
                    DispatchQueue.main.async {
                        self.imageURLs.append(url)
                    }
                }
            }
        }
    }
}
  1. 创建一个SwiftUI视图来展示相册中的RAW照片:
struct ContentView: View {
    @StateObject private var viewModel = PhotoLibraryViewModel()
    @State private var isPickerPresented = false

    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.images, id: \.self) { image in
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                        .frame(height: 100)
                }
            }
            .navigationBarTitle("RAW Photos")
            .navigationBarItems(trailing: Button(action: {
                isPickerPresented.toggle()
            }) {
                Text("选择照片")
            })
            .onAppear {
                viewModel.loadRawPhotos()
            }
            .sheet(isPresented: $isPickerPresented) {
                PhotoPickerView(images: $viewModel.images, imageURLs: $viewModel.imageURLs)
            }
        }
    }
}
  1. @main应用程序结构体中引用ContentView
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

这个示例代码展示了如何使用PHAsset从相册中获取所有RAW格式的照片,并在SwiftUI视图中使用List展示这些照片。PhotoPickerView用于打开照片选择器,选择的照片会被加载并显示在列表中。PhotoLibraryViewModel负责从相册中加载RAW照片数据。

修改代码,让列表的照片更清晰一些

为了使列表中的照片更清晰,你需要确保在加载照片时使用较高的分辨率。你可以调整请求图像的目标大小,并确保使用非同步方式加载图片以避免UI阻塞。

以下是更新后的代码:

  1. 确保在项目中导入必要的库:
import SwiftUI
import Photos
import PhotosUI
  1. 更新视图模型来请求较高分辨率的图像:
class PhotoLibraryViewModel: ObservableObject {
    @Published var images: [UIImage] = []
    @Published var imageURLs: [URL] = []

    func requestAuthorization(completion: @escaping (PHAuthorizationStatus) -> Void) {
        let status = PHPhotoLibrary.authorizationStatus()
        switch status {
        case .authorized:
            completion(.authorized)
        case .denied, .restricted, .notDetermined:
            PHPhotoLibrary.requestAuthorization { newStatus in
                DispatchQueue.main.async {
                    completion(newStatus)
                }
            }
        default:
            completion(status)
        }
    }

    func loadRawPhotos() {
        let fetchOptions = PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "mediaType == %d", PHAssetMediaType.image.rawValue)

        let allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)

        allPhotos.enumerateObjects { (asset, _, _) in
            let options = PHImageRequestOptions()
            options.isSynchronous = false
            options.deliveryMode = .highQualityFormat

            PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: 400, height: 400), contentMode: .aspectFit, options: options) { (image, info) in
                if let image = image {
                    DispatchQueue.main.async {
                        self.images.append(image)
                    }
                }
            }

            PHImageManager.default().requestImageData(for: asset, options: options) { (data, _, _, info) in
                if let url = info?["PHImageFileURLKey"] as? URL {
                    DispatchQueue.main.async {
                        self.imageURLs.append(url)
                    }
                }
            }
        }
    }
}
  1. 更新PhotoPickerView视图来展示更清晰的图像:
struct PhotoPickerView: View {
    @StateObject private var viewModel = PhotoLibraryViewModel()
    @State private var isPickerPresented = false

    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.images, id: \.self) { image in
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 200, height: 200)
                        .clipped()
                }
            }
            .listStyle(.inset)
            .navigationBarTitle("RAW Photos")
            .navigationBarItems(trailing: Button(action: {
                isPickerPresented.toggle()
            }) {
                Text("选择照片")
            })
            .onAppear {
                viewModel.requestAuthorization { status in
                    if status == .authorized {
                        viewModel.loadRawPhotos()
                    } else {
                        print("未授权访问照片库")
                    }
                }
            }
            .sheet(isPresented: $isPickerPresented) {
                PhotoPicker(images: $viewModel.images, imageURLs: $viewModel.imageURLs)
            }
        }
    }
}
  1. 更新PhotoPicker结构体:
struct PhotoPicker: UIViewControllerRepresentable {
    @Binding var images: [UIImage]
    @Binding var imageURLs: [URL]

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        var parent: PhotoPicker

        init(parent: PhotoPicker) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            for result in results {
                let provider = result.itemProvider

                if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                    provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
                        if let error = error {
                            print("Error loading file representation: \(error)")
                            return
                        }
                        guard let url = url else { return }

                        do {
                            let tempDirectory = FileManager.default.temporaryDirectory
                            let targetURL = tempDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension(url.pathExtension)

                            if FileManager.default.fileExists(atPath: targetURL.path) {
                                try FileManager.default.removeItem(at: targetURL)
                            }
                            try FileManager.default.copyItem(at: url, to: targetURL)

                            DispatchQueue.main.async {
                                self.parent.imageURLs.append(targetURL)
                                if let image = UIImage(contentsOfFile: targetURL.path) {
                                    self.parent.images.append(image)
                                }
                            }
                        } catch {
                            print("Error copying file: \(error)")
                        }
                    }
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeUIViewController(context: Context) -> PHPickerViewController {
        var configuration = PHPickerConfiguration()
        configuration.filter = .images
        configuration.selectionLimit = 0
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}
}
  1. @main应用程序结构体中引用PhotoPickerView
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            PhotoPickerView()
        }
    }
}

这些修改确保从相册中加载较高分辨率的图像,并在列表中以更清晰的方式展示这些图像。

代码中出现一个警告

'requestImageData(for:options:resultHandler:)' was deprecated in iOS 13

由于requestImageData(for:options:resultHandler:)在iOS 13中已被弃用,我们可以使用requestImageDataAndOrientation(for:options:resultHandler:)来替代它。以下是更新后的代码示例,确保在请求和加载图像数据时使用最新的API。

  1. 确保在项目中导入必要的库:
import SwiftUI
import Photos
import PhotosUI
  1. 更新视图模型来请求较高分辨率的图像,并使用新的API:
import Photos
import SwiftUI

class PhotoLibraryViewModel: ObservableObject {
    @Published var images: [UIImage] = []
    @Published var imageURLs: [URL] = []

    func requestAuthorization(completion: @escaping (PHAuthorizationStatus) -> Void) {
        let status = PHPhotoLibrary.authorizationStatus()
        switch status {
        case .authorized:
            print("Access already authorized.")
            completion(.authorized)
        case .denied, .restricted:
            print("Access denied or restricted.")
            completion(status)
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization { newStatus in
                DispatchQueue.main.async {
                    print("New authorization status: \(newStatus.rawValue)")
                    completion(newStatus)
                }
            }
        default:
            print("Unhandled authorization status: \(status.rawValue)")
            completion(status)
        }
    }

    func loadRawPhotos() {
        print("Loading RAW photos...")
        let fetchOptions = PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "mediaType == %d", PHAssetMediaType.image.rawValue)

        let allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)

        allPhotos.enumerateObjects { (asset, _, _) in
            let options = PHImageRequestOptions()
            options.isSynchronous = false
            options.deliveryMode = .highQualityFormat

            PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: 400, height: 400), contentMode: .aspectFit, options: options) { (image, info) in
                if let image = image {
                    DispatchQueue.main.async {
                        self.images.append(image)
                    }
                }
            }

            PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options) { (data, _, _, info) in
                if let url = info?["PHImageFileURLKey"] as? URL {
                    DispatchQueue.main.async {
                        self.imageURLs.append(url)
                    }
                }
            }
        }
    }
}
  1. 更新PhotoPickerView视图来展示更清晰的图像:
import SwiftUI
import PhotosUI

struct PhotoPickerView: View {
    @StateObject private var viewModel = PhotoLibraryViewModel()
    @State private var isPickerPresented = false

    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.images, id: \.self) { image in
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 200, height: 200)
                        .clipped()
                }
            }
            .listStyle(.inset)
            .navigationBarTitle("RAW Photos")
            .navigationBarItems(trailing: Button(action: {
                isPickerPresented.toggle()
            }) {
                Text("选择照片")
            })
            .onAppear {
                viewModel.requestAuthorization { status in
                    if status == .authorized {
                        viewModel.loadRawPhotos()
                    } else {
                        print("未授权访问照片库")
                    }
                }
            }
            .sheet(isPresented: $isPickerPresented) {
                PhotoPicker(images: $viewModel.images, imageURLs: $viewModel.imageURLs)
            }
        }
    }
}
  1. 更新PhotoPicker结构体:
import SwiftUI
import PhotosUI
import UniformTypeIdentifiers

struct PhotoPicker: UIViewControllerRepresentable {
    @Binding var images: [UIImage]
    @Binding var imageURLs: [URL]

    class Coordinator: NSObject, PHPickerViewControllerDelegate {
        var parent: PhotoPicker

        init(parent: PhotoPicker) {
            self.parent = parent
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)
            for result in results {
                let provider = result.itemProvider

                if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                    provider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
                        if let error = error {
                            print("Error loading file representation: \(error)")
                            return
                        }
                        guard let url = url else { return }

                        do {
                            let tempDirectory = FileManager.default.temporaryDirectory
                            let targetURL = tempDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension(url.pathExtension)

                            if FileManager.default.fileExists(atPath: targetURL.path) {
                                try FileManager.default.removeItem(at: targetURL)
                            }
                            try FileManager.default.copyItem(at: url, to: targetURL)

                            DispatchQueue.main.async {
                                self.parent.imageURLs.append(targetURL)
                                if let image = UIImage(contentsOfFile: targetURL.path) {
                                    self.parent.images.append(image)
                                }
                            }
                        } catch {
                            print("Error copying file: \(error)")
                        }
                    }
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeUIViewController(context: Context) -> PHPickerViewController {
        var configuration = PHPickerConfiguration()
        configuration.filter = .images
        configuration.selectionLimit = 0
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}
}
  1. @main应用程序结构体中引用PhotoPickerView
@main
struct YourApp: App {
    var body: some Scene {
        WindowGroup {
            PhotoPickerView()
        }
    }
}

这些修改确保在加载图像数据时使用新的requestImageDataAndOrientation(for:options:resultHandler:)方法,以替代已弃用的方法。并且确保在权限请求和处理照片库访问时更加稳定和准确。