使用ARC从NSURL和AVAudioPlayer泄漏

我是在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

负责任的图书馆 :基金会

Responsable Frame :Foundation – [NSURL(NSURL)allocWithZone:]

2。

对象 :_NSCFString

负责任的图书馆 :基金会

Responsable Frame :Foundation – [NSURL(NSURL)initFileURLWithPath:]

仪器不直接指向我的代码,所以我觉得很难find泄漏的原因。

我的问题

什么可能导致泄漏? 或者当我不对代码负责时,我怎么能find泄漏?

编辑这是从仪器周期视图架构: 在这里输入图像说明 谢谢Shani

看起来是在苹果的代码泄漏…我尝试使用两个

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

在第一种情况下,分配的AVAudioPlayer实例保留传入的NSData 。 第二,在NSURL通过保留:

我附上了一些仪器窗口的屏幕截图,显示了传入NSData对象的保留/释放历史logging。

在这里输入图像说明

您可以看到AVAudioPlayer对象,然后创build一个C ++对象AVAudioPlayerCpp ,它再次保留NSData:

在这里输入图像说明

后来,当AVAudioPlayer对象被释放时, NSData被释放,但是从来没有从关联的AVAudioPlayerCpp释放调用…(你可以从附加的图像中知道)

似乎你将不得不使用不同的解决scheme播放媒体,如果你想避免泄漏NSData / NSURL的..

这是我的testing代码:

 -(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; } 

根据以前的答案,我自己的研究和苹果开发者论坛上的讨论都指出了在iOS版本6.0,6.0.1中的苹果自己的库中存在的问题,并且据我所知也是6.0.2。

iOS 6.1已经解决了这个问题,我再也看不到漏洞了。

不幸的是,这意味着如果您认为您的应用程序将运行在仍然运行iOS 6.0,6.0.1或6.0.2版本的手机上,则必须采取解决方法来弥补这些情况的泄漏。

我们可以很好的知道,如果AVAudioPlayer初始化的所有内容都按照预期被清除,那么retainCount似乎是1。

我自己的解决方法是将播放的audio封装到自己的类中,在编译时使用-fno-objc-arc预处理器标志进行手动内存处理。

当涉及到释放所有东西的时候,我确定要获取我在初始化时使用的NSURL的保留计数(如果使用NSData进行初始化,它的工作原理是一样的),然后才能真正开始释放它。

如果一切正确处理,现在应该是1或2,所以简单地释放它适当的时间。

此外,请确保在开始发布之前获取保留计数,否则您将尝试访问已修复错误的iOS版本上的已释放对象。

这是苹果库本身的一个问题。 很多post(在stackoverflow也)已经报告了类似的问题。 这里没有什么可以做的

我的理解是,在ARC项目中工作时,作为开发人员不再负责保留/发布,因此问题出在苹果的库上,而不是你的代码。

如果这真的是苹果图书馆的一个漏洞,那么这里就不是一个有趣的解决方法。

对于所讨论的课程,使其没有启用弧。

这可以通过转到目标的构build阶段来完成。
转到编译源代码下拉菜单,find你的类的.m文件。 input-fno-objc-arc编译器标志列

不幸的是,您将需要调整类并手动pipe理内存。

关于configuration一个类不被启用弧的更详细的描述是关于SO的另一个问题上的这个答案

编辑

我想你可以将AVAudioPlayer行为封装到另一个类,并使用该类来播放所有的内容。 在这种情况下,您可以为一个文件设置-fno-objc-arc ,而不必在整个应用程序的内存pipe理