我正在编写iPhone应用程序,并且在内存方面存在一些问题。以下是代码:
NSURL *url = [curItem valueForProperty: MPMediaItemPropertyAssetURL];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL: url options:nil];
NSError *error = nil;
AVAssetReader* reader = [[AVAssetReader alloc] initWithAsset:asset error:&error];
AVAssetTrack* track = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
NSMutableDictionary* audioReadSettings = [NSMutableDictionary dictionary];
[audioReadSettings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM]
forKey:AVFormatIDKey];
AVAssetReaderTrackOutput* readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track outputSettings:audioReadSettings];
[reader addOutput:readerOutput];
[reader startReading];
CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];
while( sample != NULL)
{
sample = [readerOutput copyNextSampleBuffer];
}
CFRelease(sample);
我正在阅读用户iTunes资料库中的歌曲(curItem是当前歌曲),如果我在代码中留下最后一行:CFRelease(sample)
,程序将停止 - 没有显示错误 - 它只是崩溃。如果我注释掉这一行,我当然会遇到内存问题,并且在收到“收到内存警告”之后代码就第四首歌崩溃了。
我做错了什么?
答案 0 :(得分:1)
命名约定copyNextSampleBuffer意味着您拥有返回的对象,因此您可以正确释放它,但是您在循环中多次调用copyNextSampleBuffer方法并覆盖以前的副本而不释放它。
当你最终调用CFRelease时,你在一个刚刚检查过的变量上调用它。根据{{3}},在NULL上调用CFRelease是不安全的,这就是你崩溃的原因:
您需要做的是在覆盖变量之前在while循环中调用release,如下所示:
CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];
while( sample != NULL)
{
CFRelease(sample);
sample = [readerOutput copyNextSampleBuffer];
}
如果这不能解决您的崩溃问题(即使确实如此),请尝试在您的代码上运行静态分析器(在Xcode的产品菜单中选择Analyze),看看它是否报告任何潜在的泄漏或超过版本。请记住,你得到的每一个黄色和蓝色警告都是潜在的崩溃,所以试着解决它们。
编辑:我觉得你的循环没有多大意义 - 你为什么一遍又一遍地读取样本然后把它们扔掉?您是否在while循环中得到了NULL检查错误,而您实际上是想写这个呢?CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];
while( sample == NULL)
{
sample = [readerOutput copyNextSampleBuffer];
}
CFRelease(sample);
这也应该没问题,因为在这种情况下,您在释放之前明确检查样本是否为NULL。虽然你在做任何事情之前仍然丢弃了样本,但如果readerOutput不包含样本,你也冒着无限循环的风险。
答案 1 :(得分:0)
使用autorelease或ARC来摆脱“过早发布的综合症”。在这两种情况下,发布任务都由其他人管理。对于一个新项目,我建议使用ARC。