Превышение версии экземпляра AVAudioPlayer - PullRequest
2 голосов
/ 22 марта 2019

Очень трудно охотиться за этим. Производственное приложение периодически падает (~ 2% пользователей). Это карточная игра, поэтому на картах много постукиваний. Всякий раз, когда вы нажимаете на карту, он издает звук. Авария происходит, казалось бы, случайно, но я могу воспроизвести ее, нажав на карты некоторое время, а затем случайно произойдет сбой.

Невозможно надежно воспроизвести, но после долгих сеансов с использованием инструментов / зомби я вижу, что объект Zombie является объектом AVAudioPlayer. Это простое приложение для карточных игр (не для SK и других игровых фреймворков - все для UIKit / обычного Objective C). Я использую очень простую реализацию AVAudioPlayer. Все подробности ниже.

Трассировка стека:

Crashed: com.apple.main-thread
0  libobjc.A.dylib                0x206270d70 objc_msgSend + 16
1  Foundation                     0x207b3d42c __NSThreadPerformPerform + 336
2  CoreFoundation                 0x20701a0e0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
3  CoreFoundation                 0x20701a060 __CFRunLoopDoSource0 + 88
4  CoreFoundation                 0x207019944 __CFRunLoopDoSources0 + 176
5  CoreFoundation                 0x207014810 __CFRunLoopRun + 1040
6  CoreFoundation                 0x2070140e0 CFRunLoopRunSpecific + 436
7  GraphicsServices               0x20928d584 GSEventRunModal + 100
8  UIKitCore                      0x2343a8c00 UIApplicationMain + 212
9  <app name>                      0x1007930f0 main (main.m:14)
10 libdyld.dylib                  0x206ad2bb4 start + 4

AppDelegate.m didFinishLaunchingWithOptions

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
BOOL success = [[AVAudioSession sharedInstance] setActive:YES error:nil];

ViewController.h

@property (strong, nonatomic) AVAudioPlayer *audioPlayer;

ViewController.m

-(void) playSound:(NSString *) strSoundName {

    NSString *fileName = @"Move_1";
    NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"aif"];
    NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];

    float volume = 0.5;

    self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
    [self.audioPlayer setVolume:volume];
    [self.audioPlayer play];
}

История ссылок AVAudioPlayer enter image description here

handleTap::: - метод, который вызывает playSound

Ответы [ 2 ]

1 голос
/ 22 марта 2019

Вы проделали довольно фантастическую работу по отладке здесь. Большинство людей очень запутались из-за ошибок управления памятью / повреждения кучи, как этот.

Тем не менее, есть подсказка в том, что инструменты отслеживают, что вам нужно исследовать: зомби появляется сразу после performSelector вызова. Это заставляет меня думать, что указатель на ваш контроллер представления или на сам экземпляр AVAudioPlayer ссылается в коде, который вызывается performSelector. Так как этот код работает после освобождения контроллера представления, вы получите свой висячий указатель.

Для начала, я бы более внимательно посмотрел на то, что делает handleTap:::. Вы вызываете performSelector там? И, если это так, внимательно посмотрите, какие экземпляры вы используете для этого. Если нет, проверьте использование performSelector в других местах, чтобы увидеть, можно ли каким-то образом захватить простой указатель на ваш контроллер представления или экземпляр AVAudioPlayer.

0 голосов
/ 29 марта 2019

Никогда не мог точно понять, почему он случайно падал.

Однако мы смогли решить эту проблему, инициализируя AVAudioPlayer один раз в viewDidLoad, а затем просто вызывая play в этом методе (вместо инициализации каждый раз, когда мы хотели воспроизвести звук).

...