AVAudioPlayer 实例的过度释放
Over-release of AVAudioPlayer instance
很难找到这个。生产应用程序间歇性崩溃(约 2% 的用户)。这是一款纸牌游戏,因此需要大量点击纸牌。每当您点击卡片时,它都会发出声音。崩溃似乎是随机发生的,但我可以通过点击卡片一段时间来重现,然后它会随机崩溃。
无法可靠地重现,但在使用 Instruments/Zombies 长时间会话后,我发现 Zombie 对象是一个 AVAudioPlayer
对象。这是一个简单的纸牌游戏应用程序(不是使用 SK 或任何其他游戏框架完成的 -- 所有 UIKit/normal 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 参考历史
handleTap:::
是调用playSound
的方法
您在此处的调试工作非常出色。大多数人都被内存 management/heap 腐败错误绊倒了,就像这个。
但是,您需要调查该 Instruments 跟踪中的一条线索:僵尸在 performSelector
调用后立即出现。这让我认为 performSelector
调用的代码中引用了指向您的视图控制器或 AVAudioPlayer 实例本身的指针。由于这段代码是 运行 在视图控制器被释放之后,你得到了你的悬挂指针。
首先,我会更仔细地了解 handleTap:::
在做什么。你在那里调用 performSelector
吗?如果是这样,请仔细查看您正在使用的实例。如果没有,请审核您在其他地方对 performSelector
的使用,看看是否可以以某种方式将普通指针捕获到您的视图控制器或 AVAudioPlayer 实例。
一直无法弄清楚它随机崩溃的确切原因。
但是,我们能够通过在 viewDidLoad
中初始化一次 AVAudioPlayer
然后在该方法中调用 play
来解决问题(而不是每次我们想要初始化播放声音)。
很难找到这个。生产应用程序间歇性崩溃(约 2% 的用户)。这是一款纸牌游戏,因此需要大量点击纸牌。每当您点击卡片时,它都会发出声音。崩溃似乎是随机发生的,但我可以通过点击卡片一段时间来重现,然后它会随机崩溃。
无法可靠地重现,但在使用 Instruments/Zombies 长时间会话后,我发现 Zombie 对象是一个 AVAudioPlayer
对象。这是一个简单的纸牌游戏应用程序(不是使用 SK 或任何其他游戏框架完成的 -- 所有 UIKit/normal 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 参考历史
handleTap:::
是调用playSound
您在此处的调试工作非常出色。大多数人都被内存 management/heap 腐败错误绊倒了,就像这个。
但是,您需要调查该 Instruments 跟踪中的一条线索:僵尸在 performSelector
调用后立即出现。这让我认为 performSelector
调用的代码中引用了指向您的视图控制器或 AVAudioPlayer 实例本身的指针。由于这段代码是 运行 在视图控制器被释放之后,你得到了你的悬挂指针。
首先,我会更仔细地了解 handleTap:::
在做什么。你在那里调用 performSelector
吗?如果是这样,请仔细查看您正在使用的实例。如果没有,请审核您在其他地方对 performSelector
的使用,看看是否可以以某种方式将普通指针捕获到您的视图控制器或 AVAudioPlayer 实例。
一直无法弄清楚它随机崩溃的确切原因。
但是,我们能够通过在 viewDidLoad
中初始化一次 AVAudioPlayer
然后在该方法中调用 play
来解决问题(而不是每次我们想要初始化播放声音)。