Сбой программы в Xcode без ошибок - PullRequest
1 голос
/ 04 января 2012

Я нахожусь в процессе написания приложения для 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) в коде, программа остановится - ошибки не отображаются - она ​​просто вылетает. Если я закомментирую строку, я, конечно, столкнусь с проблемами памяти, и код вылетает примерно на четвертой песне после получения «Предупреждение о получении памяти».

Что я делаю не так?

Ответы [ 2 ]

1 голос
/ 06 января 2012

Соглашение об именах copyNextSampleBuffer подразумевает, что вы являетесь владельцем возвращенного объекта, поэтому вы правильно его отпустите, но вы вызываете метод copyNextSampleBuffer несколько раз в цикле и перезаписываете предыдущую копию, не выпуская ее.

Когда вы наконец вызываете CFRelease, вы вызываете его для переменной, которую вы только что проверили, чтобы быть NULL. Согласно этому ответу StackOverflow , вызов CFRelease для NULL небезопасен, поэтому вы терпите крах:

Вместо этого вам нужно сделать вызов call внутри цикла while, прежде чем перезаписать переменную, например:

CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];

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

Если это не исправляет ваш сбой (и даже если это так), попробуйте запустить статический анализатор над вашим кодом (выберите «Анализ» в меню продукта в XCode) и посмотрите, сообщает ли он о возможных утечках или перевыпусках. Помните, что каждое желтое и синее предупреждение, которое вы получаете, является потенциальным сбоем, поэтому попробуйте исправить их все.

РЕДАКТИРОВАТЬ: Мне просто кажется, что ваш цикл не имеет особого смысла - почему вы читаете сэмплы снова и снова, а затем просто выбрасываете их? Возможно, вы ошиблись при проверке NULL в цикле while, и вы действительно хотели написать это вместо этого?

CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];

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

CFRelease(sample);

Это также должно подойти, так как в этом случае вы явно проверяете, что сэмпл не равен NULL перед его выпуском. Хотя вы все еще выбрасываете сэмпл перед тем, как что-то с ним делать, вы рискуете получить бесконечный цикл, если readerOutput не содержит сэмплов.

0 голосов
/ 04 января 2012

Используйте либо авто-релиз, либо ARC, чтобы избавиться от «синдрома слишком раннего выпуска». В обоих случаях задача релиза управляется кем-то другим. Для нового проекта я бы предложил ARC.

...