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

Swift与Xcode:如何删除仅存在于特定相册的照片?

嘿,这个问题确实说到点子上了——苹果Photos框架的核心就是单文件多引用的机制,直接删相册里的引用会连带删掉源文件,根本做不到只删某个相册里的独有照片。不过咱们有一套可行的方案来绕开这个限制,核心思路就是先把这些“独有”照片复制成独立的新文件,再处理原文件,下面我给你拆解清楚:

核心解决思路

要实现你的需求,本质是把那些仅存在于目标相册(比如相机胶卷)的照片,从“引用”变成“独立文件”,再通过删除原文件来达到“只移除目标相册中独有照片”的效果。具体分四步:

  1. 定位目标相册,筛选出其中仅存在于该相册的照片
  2. 导出这些照片的原始数据(生成独立文件)
  3. 将导出的数据重新导入为新的独立照片(可存入自定义相册)
  4. 删除原照片(此时新照片不受影响)
具体实现步骤(Swift代码示例)

1. 权限准备

首先要在Info.plist中添加所需权限描述,否则会被系统拒权:

  • NSPhotoLibraryUsageDescription:访问照片库的原因
  • NSPhotoLibraryAddUsageDescription:添加照片的原因
  • NSPhotoLibraryDeleteUsageDescription:删除照片的原因

2. 定位目标相册(以相机胶卷为例)

func getCameraRollAlbum() -> PHAssetCollection? {
    let fetchOptions = PHFetchOptions()
    let cameraRoll = PHAssetCollection.fetchAssetCollections(
        with: .smartAlbum, 
        subtype: .smartAlbumUserLibrary, 
        options: fetchOptions
    )
    return cameraRoll.firstObject
}

3. 筛选仅存在于目标相册的照片

func fetchUniqueAssets(in targetAlbum: PHAssetCollection) -> [PHAsset] {
    let assetsFetchResult = PHAsset.fetchAssets(in: targetAlbum, options: nil)
    var uniqueAssets = [PHAsset]()
    
    assetsFetchResult.enumerateObjects { asset, _, _ in
        // 查询该照片关联的所有相册
        let relatedCollections = PHAssetCollection.fetchAssetCollectionsContaining(
            asset, 
            with: .album, 
            options: nil
        )
        var albumCount = 0
        relatedCollections.enumerateObjects { collection, _, _ in
            // 统计所有包含该照片的相册(含智能相册)
            if collection.assetCollectionType == .album || collection.assetCollectionType == .smartAlbum {
                albumCount += 1
            }
        }
        // 仅当相册数量为1时,说明这张照片只在目标相册存在
        if albumCount == 1 {
            uniqueAssets.append(asset)
        }
    }
    return uniqueAssets
}

4. 导出照片原始数据并创建独立副本

func exportAndDuplicateAsset(_ asset: PHAsset, to newAlbum: PHAssetCollection, completion: @escaping () -> Void) {
    let manager = PHImageManager.default()
    let options = PHImageRequestOptions()
    options.isNetworkAccessAllowed = true
    options.version = .original
    
    // 导出原始数据
    manager.requestImageDataAndOrientation(for: asset, options: options) { data, uti, _, _ in
        guard let imageData = data else {
            completion()
            return
        }
        
        // 把数据导入为新的独立照片,并添加到指定相册
        PHPhotoLibrary.shared().performChanges({
            let creationRequest = PHAssetCreationRequest.forAsset()
            creationRequest.addResource(with: .photo, data: imageData, options: nil)
            
            guard let placeholder = creationRequest.placeholderForCreatedAsset else {
                completion()
                return
            }
            let albumChangeRequest = PHAssetCollectionChangeRequest(for: newAlbum)
            albumChangeRequest?.addAssets([placeholder] as NSArray)
        }, completionHandler: { success, error in
            if success {
                // 副本创建成功后,删除原照片
                self.deleteOriginalAsset(asset)
            }
            completion()
        })
    }
}

// 删除原照片的方法
func deleteOriginalAsset(_ asset: PHAsset) {
    PHPhotoLibrary.shared().performChanges({
        PHAssetChangeRequest.deleteAssets([asset] as NSArray)
    }, completionHandler: { success, error in
        if let error = error {
            print("删除原照片失败:\(error.localizedDescription)")
        }
    })
}

5. 整合流程执行

func processUniqueCameraRollPhotos() {
    guard let cameraRoll = getCameraRollAlbum() else {
        print("未找到相机胶卷")
        return
    }
    
    // 先创建一个自定义相册来存放副本
    PHPhotoLibrary.shared().performChanges({
        let albumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: "独立照片副本")
        guard let placeholder = albumRequest.placeholderForCreatedAssetCollection else { return }
        let newAlbumID = placeholder.localIdentifier
        
        // 获取相机胶卷中的独有照片
        let uniqueAssets = fetchUniqueAssets(in: cameraRoll)
        
        // 遍历处理每一张照片
        for asset in uniqueAssets {
            if let newAlbum = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [newAlbumID], options: nil).firstObject {
                exportAndDuplicateAsset(asset, to: newAlbum) {}
            }
        }
    }, completionHandler: { success, error in
        if !success {
            print("创建相册失败:\(error?.localizedDescription ?? "未知错误")")
        }
    })
}
注意事项
  • 性能优化:如果处理大量照片,建议控制并发数,避免主线程阻塞,可使用串行队列或异步分组处理
  • 媒体类型兼容:上面的代码仅处理照片,如果是Live Photo或视频,需要用PHAssetResourceManager导出对应资源,再创建对应的资产类型
  • 用户确认:删除操作是永久的,一定要在执行前给用户明确的提示和确认,避免误删
  • 网络依赖:如果照片是iCloud同步的,要开启isNetworkAccessAllowed,否则无法导出原始数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:59:47