Подтвердить что ты не робот

Утечка из NSURL и AVAudioPlayer с использованием ARC

Я запускаю инструменты на iPhone 4S. Я использую AVAudioPlayer внутри этого метода:

-(void)playSound{
    NSURL *url = [self.word soundURL];
    NSError *error;
    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    if (!error) {
        [audioPlayer prepareToPlay];
        [audioPlayer play];
    }else{
       NSLog(@"Problem With audioPlayer on general card. error : %@ | url %@",[error description],[url absoluteString]);
}

У меня возникают утечки при воспроизведении звуковых файлов:

Просочившиеся объекты:

1.

Объект: NSURL

Ответственная библиотека: Foundation

Ответственный кадр: Foundation - [NSURL (NSURL) allocWithZone:]

2.

Объект: _NSCFString

Ответственная библиотека: Foundation

Ответственный кадр: Foundation - [NSURL (NSURL) initFileURLWithPath:]

Инструменты не указывают прямо на мой код, поэтому мне трудно найти причину утечки.

МОЙ ВОПРОС

Что может вызвать утечку? ИЛИ Как я могу найти утечки, когда я не несу ответственности за код?

ИЗМЕНИТЬ Это схема из цикла "Инструменты": enter image description here Спасибо Shani

4b9b3361

Ответ 1

Похоже на утечку кода Apple... Я попытался использовать оба

  • -[AVAudioPlayer initWithData:error:] и
  • -[AVAudioPlayer initWithContentsOfURL:error:]

В первом случае выделенный AVAudioPlayer экземпляр сохраняет переданный в NSData. Во втором, прошедшее в NSURL сохраняется:

Я приложил несколько снимков экрана окна "Инструменты", в которых отображается история сохранения/выпуска для переданного объекта NSData.

enter image description here

Вы можете увидеть объект AVAudioPlayer, а затем создать объект С++ AVAudioPlayerCpp, который снова сохранит NSData:

enter image description here

Позже, когда объект AVAudioPlayer освобождается, NSData отпущен, но от связанного AVAudioPlayerCpp... от имени AVAudioPlayerCpp... (вы можете сказать из прикрепленного изображения)

Кажется, вам придется использовать другое решение для воспроизведения медиафайлов, если вы хотите избежать утечки NSData/NSURL..

Здесь мой тестовый код:

-(void)timerFired:(NSTimer*)timer
{
    NSString * path = [[ NSBundle mainBundle ] pathForResource:@"song" ofType:@"mp3" ] ;

    NSError * error = nil ;
    NSData * data = [ NSData dataWithContentsOfFile:path options:NSDataReadingMapped error:&error ] ;
    if ( !data )
    {
        if ( error ) { @throw error ; }
    }

    AVAudioPlayer * audioPlayer = data ? [[AVAudioPlayer alloc] initWithData:data error:&error ] : nil ;
    if ( !audioPlayer )
    {
        if ( error ) { @throw error ; }
    }

    if ( audioPlayer )
    {
        [audioPlayer play];
        [ NSThread sleepForTimeInterval:0.75 ] ;
        [ audioPlayer stop ] ;
    }
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // ...
    [ NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector( timerFired: ) userInfo:nil repeats:YES ] ;
    // ...
    return YES;
}

Ответ 2

В соответствии с предыдущими ответами все мои собственные исследования и обсуждения на форумах разработчиков Apple указывают на проблему, которая присутствует в собственных библиотеках Apple в версиях iOS 6.0, 6.0.1 и, насколько я могу судить, 6.0.2 также.

iOS 6.1 исправил эту проблему, и я больше не могу видеть утечки.

К сожалению, это означает, что если вы считаете, что ваше приложение будет запущено на телефонах, на которых все еще работают версии 6.0, 6.0.1 или 6.0.2 iOS, вам придется обходным путем устранить утечки для этих случаев.

Что может быть полезно знать, так это то, что saveCount для того, что было использовано для инициализации AVAudioPlayer, кажется, 1, если все остальное было очищено по назначению.

Мое собственное обходное решение заключается в инкапсуляции звука, воспроизводимого в его собственном классе, для которого я выполняю ручную обработку памяти с использованием флага препроцессора -fno-objc-arc при компиляции.

Когда дело доходит до времени, чтобы освободить все, я обязательно заберу счетчик хранения NSURL, который я использовал для инициализации (будет работать так же, если инициализирован NSData), прежде чем начать его выпуск.

Если все остальное обработано правильно, то теперь оно должно быть 1 или 2, поэтому просто отпустите его в нужное количество раз.

Кроме того, убедитесь, что вы извлекли счетчик до начала выпуска, иначе вы попытаетесь получить доступ к освобожденному объекту в версиях iOS, где ошибка была исправлена.

Ответ 3

Это проблема с самой библиотекой Apple. Многие из сообщений (в stackoverflow) также сообщили о подобной проблеме. Здесь вы ничего не можете сделать.

Ответ 4

Насколько я понимаю, при работе в проектах ARC вы, как разработчик, больше не отвечаете за сохранение/выпуск, поэтому проблема связана с библиотекой Apple, а не с вашим кодом.

Ответ 5

Если это действительно ошибка в Apple Library, это не очень забавное решение.

Для рассматриваемого класса сделайте так, чтобы он не включал дугу.

Это можно сделать, перейдя к фазам сборки цели.
Перейдите к источникам компиляции и найдите файл .m для своего класса. введите -fno-objc-arc столбец флажков компилятора

К сожалению, вам нужно будет отрегулировать класс и вручную управлять памятью.

Более подробное описание для настройки класса, которое не должно быть включено дугами, было на этом ответе на другой вопрос о SO

ИЗМЕНИТЬ

Я предполагаю, что вы можете инкапсулировать поведение AVAudioPlayer в другой класс и использовать этот класс для всего воспроизведения. В этом случае вы можете установить -fno-objc-arc для одного файла и не работать с управлением памятью всего вашего приложения