使用ALAssetsLibrary的writeVideoAtPathToSavedPhotosAlbum时App随机崩溃求助
解决视频保存时的Bad Access崩溃问题
这个bad access崩溃大概率是因为异步操作中对象的生命周期管理不当,结合你的代码,我整理了几个核心的排查和解决方向:
1. 核心原因:ALAssetsLibrary实例被提前释放
writeVideoAtPathToSavedPhotosAlbum是异步方法,它的completionBlock会在操作完成后才触发。而你代码中的ALAssetsLibrary *library是局部变量,在ARC环境下,当前方法执行完毕后这个实例就会被自动释放。当后续block回调触发时,访问已经被释放的library对象就会导致野指针错误(bad access)。
修复方案:延长library的生命周期
可以通过两种方式解决:
- 将
library声明为当前类的强引用属性,确保它在block执行完成前不会被释放; - 用
__strong修饰局部变量,强制延长其生命周期:
if([[NSFileManager defaultManager] fileExistsAtPath:videoPath]) { // 用__strong修饰,避免实例被提前释放 __strong ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; [library writeVideoAtPathToSavedPhotosAlbum:[NSURL fileURLWithPath:videoPath] completionBlock:^(NSURL *assetURL, NSError *error) { if (error) { NSLog(@"视频保存失败:%@", error.localizedDescription); } // 操作完成后可以清理缓存文件 [[NSFileManager defaultManager] removeItemAtPath:videoPath error:nil]; }]; }
2. 补充:增加边界检查避免潜在崩溃
你的代码还有几个可以优化的边界点,虽然不是这次崩溃的直接原因,但能避免其他潜在问题:
- 检查
arrjid的数组长度:如果jid为空或者不包含@符号,componentsSeparatedByString会返回包含原字符串的数组,但最好加上判断避免意外:NSString *jidPrefix = arrjid.count > 0 ? arrjid[0] : @"unknown_user"; - 检查缓存目录是否存在:
NSSearchPathForDirectoriesInDomains理论上不会返回空数组,但加上判断更稳妥:NSArray *cacheDirs = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); if (cacheDirs.count == 0) { NSLog(@"无法获取缓存目录"); return; } - 检查视频数据写入是否成功:
writeToFile会返回BOOL值,建议判断写入结果再执行后续操作:BOOL writeSuccess = [videoData writeToFile:videoPath atomically:YES]; if (!writeSuccess) { NSLog(@"视频数据写入失败"); return; }
3. 长远方案:替换为更稳定的Photos框架
ALAssetsLibrary在iOS 9之后已经被官方弃用,推荐使用Photos框架来处理相册操作,不仅更稳定,还能获得更好的兼容性:
// 记得导入Photos框架 #import <Photos/Photos.h> // ... 前面的路径处理代码 ... if([[NSFileManager defaultManager] fileExistsAtPath:videoPath]) { [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ // 创建视频保存请求 PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:videoPath]]; } completionHandler:^(BOOL success, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ if (success) { NSLog(@"视频保存到相册成功"); } else { NSLog(@"视频保存失败:%@", error.localizedDescription); } // 清理缓存文件 [[NSFileManager defaultManager] removeItemAtPath:videoPath error:nil]; }); }]; }
额外提醒:检查相册权限
确保你的App已经申请了相册访问权限,在Info.plist中添加对应的权限描述(NSPhotoLibraryAddUsageDescription和NSPhotoLibraryUsageDescription),虽然权限问题不会直接导致bad access,但会引发保存失败的错误。
内容的提问来源于stack exchange,提问作者shraddha k vaishanani
相关产品推荐
相关产品推荐

