iOS Photo Framework编辑JPEG图片报错及还原/缩略图异常求助
咱们一步步拆解你的问题:先搞懂那个诡异的错误码,再解决没有还原选项的问题,最后搞定缩略图不更新的情况。
首先说那个看起来吓人的错误码:code: 18446744073709551615其实是无符号64位整数的最大值,转成有符号整数就是-1——这意味着Photos框架或底层CGImage操作返回了一个未明确的通用错误,核心原因是你绕过了Photos编辑流程的规范逻辑。
核心问题:错误的文件写入路径
你现在直接把修改后的数据写入contentEditingInput.fullSizeImageURL,这是Photos库的原始文件路径,Photos框架不允许直接修改这个路径的文件!正确的做法是写入PHContentEditingOutput提供的renderedContentURL——这是Photos为编辑操作分配的临时路径,之后由Photos框架自动处理归档、更新缩略图和提供还原选项。
具体代码修正步骤
1. 修复文件写入逻辑
把直接写入原URL的代码替换为写入output的渲染URL:
// 替换原来的 [dest_data writeToURL:fileUrl atomically:YES]; BOOL writeSuccess = [dest_data writeToURL:output.renderedContentURL atomically:YES];
2. 修正AdjustmentData,找回还原选项
你的adjustmentData用空字符串归档,会导致Photos无法识别这是一个可撤销的编辑操作。你应该归档实际的编辑参数(哪怕是空字典也比空字符串合理),同时确保格式标识的唯一性:
// 归档你的编辑参数,比如修改的元数据metaDict NSData *adjustmentData = [NSKeyedArchiver archivedDataWithRootObject:metaDict]; output.adjustmentData = [[PHAdjustmentData alloc] initWithFormatIdentifier:@"com.yourcompany.yourapp.imageedit" formatVersion:@"1.0" data:adjustmentData];
提示:
formatIdentifier建议用你App的反向域名(比如com.yourapp.photoedit),确保和其他App的编辑格式不冲突;formatVersion用于后续编辑逻辑迭代时区分版本。
3. 修复逻辑漏洞与错误处理
- 把代码里的
success && completionBlock修正为success && completionBlock(这是HTML转义错误,实际代码要写正确的逻辑与运算符) - 增加文件写入的错误检查,避免后续流程无意义执行:
if (!writeSuccess) { if (completionBlock) { NSError *writeError = [NSError errorWithDomain:@"YourAppEditError" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"写入编辑后图片失败"}]; completionBlock(writeError, nil); } return; }
4. 确保缩略图自动更新
当你正确使用PHAssetChangeRequest并设置contentEditingOutput后,Photos框架会自动处理缩略图的更新,不需要手动刷新。如果之前直接修改过原文件,建议重启Photos App或者通过PHPhotoLibrary的变更监听来触发UI刷新。
修正后的关键代码片段
[asset requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) { PHContentEditingOutput *output = [[PHContentEditingOutput alloc] initWithContentEditingInput:contentEditingInput]; // 生成正确的AdjustmentData NSData *adjustmentData = [NSKeyedArchiver archivedDataWithRootObject:metaDict]; output.adjustmentData = [[PHAdjustmentData alloc] initWithFormatIdentifier:@"com.yourcompany.yourapp.imageedit" formatVersion:@"1.0" data:adjustmentData]; // 写入到Photos指定的渲染路径 BOOL writeSuccess = [dest_data writeToURL:output.renderedContentURL atomically:YES]; if (!writeSuccess) { if (completionBlock) { NSError *writeError = [NSError errorWithDomain:@"YourAppEditError" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"写入编辑后图片失败"}]; completionBlock(writeError, nil); } return; } if([asset canPerformEditOperation:PHAssetEditOperationContent]){ [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:asset]; request.contentEditingOutput = output; } completionHandler:^(BOOL success, NSError *error) { if (success && completionBlock) { completionBlock(nil, output.renderedContentURL); } else { if (completionBlock) { completionBlock(error, nil); } } }]; } }];
额外排查点
- 检查
metaDict是否包含符合JPEG规范的元数据,避免CGImageDestinationFinalize失败 - 确认
imageData是有效的JPEG数据,可以用CGImageSourceGetCount(source)验证是否能正确识别图片 - 确保App已获得
PHAuthorizationStatusAuthorized级别的Photos权限,权限不足也可能导致隐藏错误
内容的提问来源于stack exchange,提问作者Pankaj Goyal




