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

iOS相册批量编辑:PHAssetChangeRequest报错与单权限弹窗实现

解决方案

问题根源

  1. 原代码中requestContentEditingInput是异步方法,它的回调会在performChanges的事务闭包执行完毕后才触发,此时已不在照片库的事务上下文内,创建PHAssetChangeRequest会触发权限报错。
  2. 若直接在performChanges闭包内同步创建修改请求,会因每张照片单独触发权限校验,导致多次弹窗。

正确实现思路

要实现批量修改仅弹一次权限弹窗,必须:

  • 先异步批量获取所有选中照片的编辑输入并完成图片处理,生成对应的PHContentEditingOutput
  • 待所有处理完成后,在同一个performChanges事务内批量提交所有修改请求,系统会自动合并权限校验,只弹出一次确认框

代码实现

let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = { adjustmentData -> Bool in
    adjustmentData.formatIdentifier == AdjustmentFormatIdentifier && adjustmentData.formatVersion == "1.0"
}

// 用字典保存每个资产对应的编辑输出
var assetOutputMap: [PHAsset: PHContentEditingOutput] = [:]
let dispatchGroup = DispatchGroup()

for asset in imageAssets {
    guard let asset = asset else { continue }
    dispatchGroup.enter()
    
    asset.requestContentEditingInput(with: options) { contentEditingInput, info in
        defer { dispatchGroup.leave() }
        
        guard let contentEditingInput = contentEditingInput else {
            // 处理获取编辑输入失败的情况
            return
        }
        
        // 1. 加载并处理图片
        let url = contentEditingInput.fullSizeImageURL!
        let orientation = contentEditingInput.fullSizeImageOrientation
        guard var inputImage = CIImage(contentsOf: url) else { return }
        inputImage = inputImage.oriented(forExifOrientation: orientation)
        
        // 2. 应用变换滤镜
        let transformFilter = CIFilter.lanczosScaleTransform()
        transformFilter.inputImage = inputImage
        transformFilter.scale = 1
        transformFilter.aspectRatio = Float(stretchFactor)
        
        guard let outputImage = transformFilter.outputImage else { return }
        
        // 3. 创建调整数据
        let filterData = withUnsafeBytes(of: stretchFactor) { Data($0) }
        let adjustmentData = PHAdjustmentData(formatIdentifier: AdjustmentFormatIdentifier, formatVersion: "1.0", data: filterData)
        
        // 4. 生成编辑输出并写入图片数据
        let contentEditingOutput = PHContentEditingOutput(contentEditingInput: contentEditingInput)
        let jpegData = UIImage(ciImage: outputImage, scale: displayScale, orientation: .up).jpegData(compressionQuality: 1)
        
        do {
            try jpegData?.write(to: contentEditingOutput.renderedContentURL, options: .atomic)
            contentEditingOutput.adjustmentData = adjustmentData
            assetOutputMap[asset] = contentEditingOutput
        } catch {
            // 处理写入失败的情况
        }
    }
}

// 所有图片处理完成后,统一提交修改
dispatchGroup.notify(queue: .main) {
    PHPhotoLibrary.shared().performChanges({
        for (asset, output) in assetOutputMap {
            let request = PHAssetChangeRequest(for: asset)
            request.contentEditingOutput = output
        }
    }, completionHandler: { success, error in
        if success {
            isPresented = false
        } else {
            // 处理修改失败的情况
        }
    })
}

关键说明

  • 使用DispatchGroup等待所有异步图片处理任务完成,确保所有PHContentEditingOutput准备就绪后再提交事务。
  • 所有PHAssetChangeRequest在同一个performChanges闭包内创建,系统会识别为批量操作,仅弹出一次权限确认弹窗(显示修改照片总数)。
  • 异步处理图片编辑的逻辑被移出performChanges事务,避免了事务超时或上下文失效的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 10:43:14