Swift与Xcode:如何删除仅存在于特定相册的照片?
嘿,这个问题确实说到点子上了——苹果Photos框架的核心就是单文件多引用的机制,直接删相册里的引用会连带删掉源文件,根本做不到只删某个相册里的独有照片。不过咱们有一套可行的方案来绕开这个限制,核心思路就是先把这些“独有”照片复制成独立的新文件,再处理原文件,下面我给你拆解清楚:
核心解决思路
要实现你的需求,本质是把那些仅存在于目标相册(比如相机胶卷)的照片,从“引用”变成“独立文件”,再通过删除原文件来达到“只移除目标相册中独有照片”的效果。具体分四步:
- 定位目标相册,筛选出其中仅存在于该相册的照片
- 导出这些照片的原始数据(生成独立文件)
- 将导出的数据重新导入为新的独立照片(可存入自定义相册)
- 删除原照片(此时新照片不受影响)
具体实现步骤(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
相关产品推荐
相关产品推荐

