使用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理