7

这不是一个问题,而是我在 Apple 为 iOS4 和 5 相机操作提供的 AVCam 示例代码中发现的内容的记录。对我来说,问题的症状是我的应用在拍摄了大约 5-10 张照片后在启动 AVCamViewController 时会崩溃。

我通过内存泄漏分析器运行该应用程序,没有明显的泄漏,但在使用 Activity Monitor 检查时,我发现每次启动相机时,名为 mediaserverd 的东西都会增加 17Mb,当它达到 ~100Mb 时,应用程序会因多个低点而崩溃内存警告。

4

3 回答 3

16

我做的第一件事是将日志记录到所有 AVCam 文件的 dealloc 方法中。我很快发现 AVCamCaptureManager 和 AVCamRecorder 没有在 AVCamViewController 被释放时被释放。我检查了保留和释放调用,它们似乎平衡了,所以我在 [captureManager 释放] 上放置了一个断点,发现它在释放后具有 2 的 retainCount (因此没有调用 AVCamCaptureManager 释放)。

接下来,我逐步完成了捕获管理器的创建过程,并发现它在调用 init 方法后立即具有 3 的保留计数。

逐步执行 init 方法并检查每一行的保留计数,我发现以下两行都在增加保留计数:

[self setDeviceConnectedObserver=[notificationCenter addObserverForName:AVCaptureDeviceWasConnectedNotification object:nil queue:nil usingBlock:deviceConnectedBlock]];
[self setDeviceDisconnectedObserver=[notificationCenter addObserverForName:AVCaptureDeviceWasDisconnectedNotification object:nil queue:nil usingBlock:deviceDisconnectedBlock]];

通过查看,我发现 removeObserver 对应项位于 AVCamCaptureManager 的 dealloc 方法中(没有被调用),因此保留计数从未下降到 0。

为了修复它,我创建了一个新的公共 removeObservers 方法:

 -(void)removeObservers {
     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
     [notificationCenter removeObserver:[self deviceConnectedObserver]];
     [notificationCenter removeObserver:[self deviceConnectedObserver]];
 }

并从 AVCamCaptureManager dealloc 方法中取出相同的行。

调用 [captureManager removeObservers];然后调用 [captureManager release]; 在 AVCamViewController dealloc 方法中成功将保留计数降至 0。

使用 Activity Monitor 进行测试时,现在 mediaserverd 进程的嗡嗡声只有 5-17Mb,并且崩溃停止了!

希望这可以帮助其他遇到此问题的人!

于 2011-10-25T01:45:38.013 回答
4

Apple 于 2013 年 10 月 17 日修改了示例代码,修复了保留周期。该问题是由于selfinit.

这是修订说明

修复AVCaptureManager了导致泄漏的保留周期。注意- 如果你AVCam在你的应用程序中修改了代码,你应该采用在AVCaptureManager.m'sinit方法中所做的修复。如果没有这些修复,您可能会泄漏AVCaptureManager实例并让相机在您的应用程序处于前台时持续运行。


但是,他们引入的修复仅适用于手动保留计数。如果您在项目中使用 ARC,除了摆脱release/retain调用和其他明显的东西之外,存储限定符 forweakSelf必须从更改__block__weak,如下所示。

__weak AVCamCaptureManager *weakSelf = self;

实际上__block用ARC改变了语义。在 MRC 中,它导致变量被弱引用,而在 ARC 中,它没有并且__weak必须用于此目的。

可以在此处找到有关此主题的更多信息:如何在实现 API 时避免在块中捕获自我?

使用上一个修订版中的新init实现并使用__weak而不是__block,最终导致该dealloc方法被正确调用。


最后,对于那些讨厌携带旧代码的人,这里是该AVCam项目的现代化版本:https ://github.com/Gabro/AVCam

特征:

  • 无内存泄漏
  • 使用 ARC
  • 现代 Objective-C 语法
  • iOS 7 的次要 UI 修复
于 2013-11-01T15:50:46.443 回答
2

最近碰到这个问题。我发现真正的根本问题是 deviceConnectedBlock 和 deviceDisconnectedBlock 隐含地引用自我,导致保留循环。要修复它,请将这些块中的所有 ivar 引用更改为使用 weakSelf。

这样,您就不需要记住显式调用拆卸方法。

希望这对其他人有帮助。

REF:使用 NSNotificationCenter 代码块方法和 ARC 时未调用视图控制器 dealloc

于 2013-07-19T02:52:59.513 回答