【问题标题】:Program crashing in Xcode with no error shown程序在 Xcode 中崩溃,没有显示错误
【发布时间】:2012-01-04 19:01:09
【问题描述】:

我正在编写 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),程序将停止 - 没有显示错误 - 它只是崩溃。如果我注释掉这行,我当然会遇到内存问题,并且代码在收到“收到内存警告”后大约在第四首歌曲崩溃。

我做错了什么?

【问题讨论】:

    标签: iphone memory-management avassetreader


    【解决方案1】:

    命名约定 copyNextSampleBuffer 意味着您拥有返回的对象,因此您可以正确释放它,但是您在循环中多次调用 copyNextSampleBuffer 方法并覆盖之前的副本而不释放它。

    当您最终调用 CFRelease 时,您是在一个刚刚检查为 NULL 的变量上调用它。根据this StackOverflow answer,在 NULL 上调用 CFRelease 是不安全的,所以这就是你崩溃的原因:

    您需要做的是在覆盖变量之前在 while 循环中调用 release,如下所示:

    CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];
    
    while( sample != NULL)
    {
        CFRelease(sample);
        sample = [readerOutput copyNextSampleBuffer];
    }
    

    如果这不能解决您的崩溃问题(即使解决了),请尝试在您的代码上运行静态分析器(在 Xcode 的产品菜单中选择“分析”),看看它是否报告了任何潜在的泄漏或过度发布。请记住,您收到的每个黄色和蓝色警告都是潜在的崩溃,因此请尝试将它们全部修复。

    编辑:我突然想到你的循环没有多大意义 - 为什么你一遍又一遍地阅读样本然后把它们扔掉?你是不是在你的 while 循环中弄错了 NULL 检查,而你实际上是想写这个?

    CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];
    
    while( sample == NULL)
    {
        sample = [readerOutput copyNextSampleBuffer];
    }
    
    CFRelease(sample);
    

    这也应该没问题,因为在这种情况下,您在释放样本之前明确检查样本不为 NULL。尽管在对样本进行任何操作之前您仍然会丢弃样本,并且如果 readerOutput 不包含样本,您也会面临无限循环的风险。

    【讨论】:

      【解决方案2】:

      使用自动释放或 ARC 来摆脱“过早释放综合症”。在这两种情况下,发布任务都由其他人管理。对于一个新项目,我建议使用 ARC。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多