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

SwiftUI选择照片解析后删除:itemIdentifier始终为nil的解决求助

问题:SwiftUI PhotosPicker无法获取itemIdentifier实现图片删除

我开发了一款SwiftUI应用,支持用户选择图片解析内容并保存,这部分功能已实现。现在希望在解析完成后,将用户所选图片从照片库中删除,但遇到了itemIdentifier始终为nil的问题,无法获取assetIdentifier执行删除操作。

简化版代码如下:

import SwiftUI
import PhotosUI

struct NewItemView: View {
    
    @State private var shouldDeleteImage = true
    @State private var photosPickerItem: PhotosPickerItem?
    @State private var isBeingParsed = false // 补充缺失的状态变量
    
    var body: some View {
        NavigationView {
            Form {
                Section("image") {
                    PhotosPicker(selection: $photosPickerItem) {
                        Label("Select a Duolingo Photo", systemImage: "photo")
                    }
                }
                .onChange(of: photosPickerItem) { selectedPhotosPickerItem in
                    guard let selectedPhotosPickerItem else {
                        return
                    }
                    debugPrint(selectedPhotosPickerItem)
                    
                    Task {
                        isBeingParsed = true
                        await updatePhotosPickerItem(with: selectedPhotosPickerItem)
                        isBeingParsed = false
                    }
                }
                
                Section("Parsed content") {
                    // 展示解析内容
                }
            }
            .navigationTitle("New item")
        }
    }
    
    private func updatePhotosPickerItem(with item: PhotosPickerItem) async {
        photosPickerItem = item
        if let photoData = try? await item.loadTransferable(type: Data.self) {
            let image = UIImage(data: photoData)
            // 处理图片逻辑
            // 💥 报错:itemIdentifier始终为nil
            self.deleteImage(assetIdentifier: item.itemIdentifier!)
        }
    }
    
    private func deleteImage(assetIdentifier: String) {
        let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier], options: nil)
        guard let asset = fetchResult.firstObject else { return }
        PHPhotoLibrary.shared().performChanges {
            PHAssetChangeRequest.deleteAssets([asset] as NSArray)
        } completionHandler: { success, error in
            if success {
                print("Image deleted from photo library")
            } else {
                print("Error deleting image from photo library: \(error?.localizedDescription ?? "unknown error")")
            }
        }
    }
}

解决方法

方案1:直接绑定PHAsset类型(推荐)

放弃使用PhotosPickerItem,直接让PhotosPicker选择PHAsset对象,这样可以直接获取到资产的localIdentifier,无需依赖itemIdentifier。

步骤:

  1. 导入Photos框架
  2. 修改选择器的绑定类型为PHAsset?
  3. 设置图片过滤规则,确保只选择图片
  4. 监听资产变化,直接使用asset.localIdentifier执行删除

修改后的关键代码:

import SwiftUI
import PhotosUI
import Photos // 新增导入

struct NewItemView: View {
    
    @State private var shouldDeleteImage = true
    @State private var selectedAsset: PHAsset? // 修改为PHAsset类型
    @State private var isBeingParsed = false
    
    var body: some View {
        NavigationView {
            Form {
                Section("image") {
                    PhotosPicker(
                        selection: $selectedAsset,
                        matching: .images // 只选择图片
                    ) {
                        Label("Select a Duolingo Photo", systemImage: "photo")
                    }
                }
                .onChange(of: selectedAsset) { asset in
                    guard let asset else { return }
                    
                    Task {
                        isBeingParsed = true
                        await processSelectedAsset(asset)
                        isBeingParsed = false
                    }
                }
                
                Section("Parsed content") {
                    // 展示解析内容
                }
            }
            .navigationTitle("New item")
            .onAppear {
                // 提前请求相册权限
                Task {
                    await requestPhotoLibraryPermission()
                }
            }
        }
    }
    
    // 请求相册读写权限
    private func requestPhotoLibraryPermission() async {
        let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
        if status == .notDetermined {
            _ = await PHPhotoLibrary.requestAuthorization(for: .readWrite)
        }
    }
    
    private func processSelectedAsset(_ asset: PHAsset) async {
        // 从PHAsset加载图片数据
        let options = PHImageRequestOptions()
        options.isSynchronous = true
        var imageData: Data?
        
        PHImageManager.default().requestImageDataAndOrientation(
            for: asset,
            options: options
        ) { data, _, _, _ in
            imageData = data
        }
        
        guard let data = imageData else { return }
        let image = UIImage(data: data)
        // 处理图片逻辑
        
        // 直接使用asset的localIdentifier删除
        deleteImage(assetIdentifier: asset.localIdentifier)
    }
    
    private func deleteImage(assetIdentifier: String) {
        // 原删除逻辑不变
        let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier], options: nil)
        guard let asset = fetchResult.firstObject else { return }
        PHPhotoLibrary.shared().performChanges {
            PHAssetChangeRequest.deleteAssets([asset] as NSArray)
        } completionHandler: { success, error in
            if success {
                print("Image deleted from photo library")
            } else {
                print("Error deleting image from photo library: \(error?.localizedDescription ?? "unknown error")")
            }
        }
    }
}

方案2:通过PhotosPickerItem加载PHAsset

如果必须使用PhotosPickerItem,可以尝试直接从item中加载PHAsset类型,而不是先加载Data。注意这种方法并非在所有场景下都有效,但可以尝试:

修改updatePhotosPickerItem方法:

private func updatePhotosPickerItem(with item: PhotosPickerItem) async {
    photosPickerItem = item
    // 尝试加载PHAsset
    if let asset = try? await item.loadTransferable(type: PHAsset.self) {
        // 加载图片数据
        let options = PHImageRequestOptions()
        options.isSynchronous = true
        var imageData: Data?
        
        PHImageManager.default().requestImageDataAndOrientation(
            for: asset,
            options: options
        ) { data, _, _, _ in
            imageData = data
        }
        
        guard let data = imageData else { return }
        let image = UIImage(data: data)
        // 处理图片逻辑
        
        // 使用asset的localIdentifier删除
        deleteImage(assetIdentifier: asset.localIdentifier)
    }
}

注意事项

  • 必须确保应用拥有相册的读写权限,在Info.plist中添加以下键值对:
    • NSPhotoLibraryUsageDescription:说明访问相册的原因
    • NSPhotoLibraryAddUsageDescription:说明修改/删除相册内容的原因
  • 删除操作会直接移除相册中的图片,建议在执行前添加用户确认提示,避免误删。

内容的提问来源于stack exchange,提问作者Sahbi Belgacem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:14:55