iphone - 我的 block 没有保留它的一些对象

标签 iphone objective-c ios4 objective-c-blocks

来自 block 文档:

In a reference-counted environment, by default when you reference an Objective-C object within a block, it is retained. This is true even if you simply reference an instance variable of the object.

我正在尝试实现一个完成处理程序模式,其中在执行工作之前向对象提供一个 block ,并在执行工作之后由接收者执行该 block 。由于我是一个良好的内存公民,因此该 block 应该拥有它在完成处理程序中引用的对象,然后当该 block 超出范围时它们将被释放。我知道,我必须复制该 block 才能将其移动到堆,因为该 block 将在声明它的堆栈范围内生存。

但是,我的一个对象意外地被释放。经过一番尝试后,发现当 block 复制到堆时,某些对象不会被保留,而其他对象则会被保留。我不确定我做错了什么。这是我可以生成的最小测试用例:

typedef void (^ActionBlock)(UIView*);

在某些方法的范围内:

NSObject *o = [[[NSObject alloc] init] autorelease];
mailViewController = [[[MFMailComposeViewController alloc] init] autorelease];
NSLog(@"o's retain count is %d",[o retainCount]);
NSLog(@"mailViewController's retain count is %d",[mailViewController retainCount]);
ActionBlock myBlock = ^(UIView *view) {
       [mailViewController setCcRecipients:[NSArray arrayWithObjects:@"<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dfabbaacab9fadbabcb6afb6bab1abf1bcb0b2" rel="noreferrer noopener nofollow">[email protected]</a>",nil]];
       [o class];
    };
NSLog(@"mailViewController's retain count after the block is %d",[mailViewController retainCount]);
NSLog(@"o's retain count after the block is %d",[o retainCount]);
Block_copy(myBlock);
NSLog(@"o's retain count after the copy is %d",[o retainCount]);
NSLog(@"mailViewController's retain count after the copy is %d",[mailViewController retainCount]);

我希望这两个对象在某个时刻都被 block 保留,并且我当然希望它们的保留计数相同。相反,我得到以下输出:

o's retain count is 1
mailViewController's retain count is 1
mailViewController's retain count after the block is 1
o's retain count after the block is 1
o's retain count after the copy is 2
mailViewController's retain count after the copy is 1

o(NSObject 的子类)已正确保留,并且不会超出范围。但是 mailViewController 不会被保留,并且会在 block 运行之前被释放,从而导致崩溃。

最佳答案

不要使用-retainCount。

对象的绝对保留计数是没有意义的。

您应该调用 release 的次数与导致对象被保留的次数完全相同。不能少(除非您喜欢泄漏),当然也不能多(除非您喜欢崩溃)。

请参阅Memory Management Guidelines了解完整详细信息。

(摘自@bbum的一个答案)


至于你的问题:

您真的观察到崩溃吗?或者你只是盲目地从臀部射击并认为它可能会崩溃?

从您发布的代码来看,mailViewController 似乎是一个实例变量,在这种情况下,该 block 将保留 self 而不是实例变量。由于您自动释放了您的实例变量,它会被 NSAutoreleasePool 清理,就像您所期望的那样。

总结一下:

  1. 请勿使用-retainCount
  2. 不要自动释放您希望在本轮运行循环之外存在的实例变量。

编辑更多说明:

以下是创建 block 时会发生的情况:

  1. 检查其范围内的对象引用。有两个:self->mailViewControllero
  2. self->mailViewController 是结构体 (self) 的成员,因此不会直接保留。而是保留 self
  3. o 是局部变量。保留它。

这是正确的行为。至于你的代码...

  1. o 创建时保留计数为 +0
  2. self->mailViewController 创建时保留计数为 +0
  3. myBlock 创建时保留计数为 +0。 o 现在有 +1 RC,self 也是如此。 self->mailViewController 仍然有 +0 RC
  4. myBlock 已复制 => +1 保留计数

快进到此运行循环周期的末尾。

  1. 当前自动释放池已耗尽。所有保留计数为 +0 的对象都将被释放,包括 self->mailViewControllerself->mailViewController 现在指向已释放的内存,本质上是垃圾。

执行myBlock时快进到某个 future 点

  1. myBlock 尝试调用 self->mailViewController 上的方法。但是,self->mailViewController 不再指向有效对象,您的应用会崩溃。

但是,如果mailViewController不是实例变量,那么我们需要查看更多代码。我认为您所看到的行为不太可能是 block 运行时的问题,但有可能。

关于iphone - 我的 block 没有保留它的一些对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4587954/

相关文章:

iPhone SDK : Flip-and-scale animation between view controllers using blocks?

iPhone 在视频播放后强制方向

iphone - UIImagePNGRepresentation() 和比例(iPhone 4 屏幕)

iphone - 触摸开始驳回 View

iphone - 协作/构建大型 Phonegap 项目

iphone - 具有自定义 rightView 的 UITextField 中的宽度问题

objective-c - 使用开始日期获取 iPhone 日历中的所有事件

iphone - 将 long long 转换为字符串

objective-c - 如何使用 NSManagedObjectSubClass 从 CoreData Base 获取所有记录?

objective-c - 只有成功才能在 SenTest 中运行代码的任何方法?