iOS17及以上版本AVMutableComposition insertTimeRange方法崩溃排查求助
iOS17+下AVMutableComposition insertTimeRange崩溃排查
崩溃现象
Firebase上报少量崩溃案例:调用AVMutableComposition的insertTimeRange:ofAsset:atTime:error:方法时,抛出-[__NSArrayM insertObject:atIndex:]: object cannot be nil异常,且多数发生在iOS17.0及以上版本。
用户实现代码:
- (AVMutableComposition *)createtrimAsset:(AVAsset *)asset andStartTime:(CGFloat)startTime endTime:(CGFloat)endTime{ NSError *error = nil; CGFloat timescale = 1000000; AVMutableComposition *mutableComposition = [AVMutableComposition composition]; CMTime sStartTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(asset.duration)*startTime, timescale); CMTime eEndTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(asset.duration)*endTime, timescale); [mutableComposition insertTimeRange:CMTimeRangeMake(sStartTime, CMTimeSubtract(eEndTime, sStartTime)) ofAsset:asset atTime:kCMTimeZero error:&error]; return mutableComposition; }
用户已尝试设置asset=nil、asset.duration=0或NAN等场景,均未复现崩溃。
可能触发原因
- 时间范围合法性问题:若传入的
startTime >= endTime,会导致计算出的时间范围时长为负或零;或时间范围超出asset的实际时长,iOS17的AVFoundation内部处理此类非法参数时,可能尝试插入nil对象到数组,引发崩溃。 - Asset未完全加载:同步获取
asset.duration时,若asset是网络资源、iCloud资源或未完成加载的本地资源,CMTimeGetSeconds(asset.duration)可能返回无效值(如NAN),导致时间范围计算异常,触发内部逻辑崩溃。 - Asset的Track异常:
asset本身有效,但内部无可用track(如损坏的视频文件、格式不兼容的资源),iOS17对这类场景的处理逻辑与旧版本不同,内部尝试添加nil track到数组时崩溃。 - iOS17 AVFoundation行为变更:iOS17对
AVMutableComposition的参数校验逻辑更严格,某些在旧版本中仅返回error的非法操作,现在会直接触发内部崩溃。
排查建议
校验时间范围合法性:
添加前置判断,确保时间范围有效且未超出asset时长:if (startTime >= endTime) return nil; CMTime assetDuration = asset.duration; CGFloat assetDurationSec = CMTimeGetSeconds(assetDuration); if (isnan(assetDurationSec) || assetDurationSec <= 0) return nil; CMTime sStartTime = CMTimeMakeWithSeconds(assetDurationSec * startTime, timescale); CMTime eEndTime = CMTimeMakeWithSeconds(assetDurationSec * endTime, timescale); if (CMTimeCompare(sStartTime, assetDuration) >= 0 || CMTimeCompare(eEndTime, assetDuration) > 0) return nil; CMTime rangeDuration = CMTimeSubtract(eEndTime, sStartTime); if (CMTimeCompare(rangeDuration, kCMTimeZero) <= 0) return nil;异步加载Asset属性:
避免同步读取未加载完成的asset属性,改用异步加载确保数据有效:[asset loadValuesAsynchronouslyForKeys:@[@"duration", @"tracks"] completionHandler:^{ NSError *error = nil; AVKeyValueStatus durationStatus = [asset statusOfValueForKey:@"duration" error:&error]; AVKeyValueStatus tracksStatus = [asset statusOfValueForKey:@"tracks" error:&error]; if (durationStatus == AVKeyValueStatusLoaded && tracksStatus == AVKeyValueStatusLoaded && asset.tracks.count > 0) { // 在此执行trim逻辑 AVMutableComposition *composition = [self createtrimAsset:asset andStartTime:startTime endTime:endTime]; // 回调处理结果 } else { // 处理加载失败或无track的情况 } }];检查并处理Error:
调用insertTimeRange后务必检查error参数,获取更多崩溃线索:BOOL success = [mutableComposition insertTimeRange:range ofAsset:asset atTime:kCMTimeZero error:&error]; if (!success) { NSLog(@"Insert time range failed: %@", error); return nil; }测试特殊Asset场景:
针对iOS17,测试以下场景是否能复现崩溃:- HEVC格式视频、Live Photo导出的视频资源
- 未下载完成的iCloud视频
- 损坏/不兼容格式的视频文件
- 时长极短(如小于1秒)的视频
校验Asset的Track状态:
在调用insertTimeRange前,确保asset存在可用track:if (!asset || asset.tracks.count == 0) return nil;
内容的提问来源于stack exchange,提问作者yongfeng jin
相关产品推荐
相关产品推荐

