来自 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
清理,就像您所期望的那样。
总结一下:
- 请勿使用
-retainCount
。 - 不要
自动释放
您希望在本轮运行循环之外存在的实例变量。
编辑更多说明:
以下是创建 block 时会发生的情况:
- 检查其范围内的对象引用。有两个:
self->mailViewController
和o
。 self->mailViewController
是结构体 (self
) 的成员,因此不会直接保留。而是保留self
。o
是局部变量。保留它。
这是正确的行为。至于你的代码...
o
创建时保留计数为 +0self->mailViewController
创建时保留计数为 +0myBlock
创建时保留计数为 +0。o
现在有 +1 RC,self
也是如此。self->mailViewController
仍然有 +0 RCmyBlock
已复制 => +1 保留计数
快进到此运行循环周期的末尾。
- 当前自动释放池已耗尽。所有保留计数为 +0 的对象都将被释放,包括
self->mailViewController
。self->mailViewController
现在指向已释放的内存,本质上是垃圾。
执行myBlock
时快进到某个 future 点
myBlock
尝试调用self->mailViewController
上的方法。但是,self->mailViewController
不再指向有效对象,您的应用会崩溃。
但是,如果mailViewController
不是实例变量,那么我们需要查看更多代码。我认为您所看到的行为不太可能是 block 运行时的问题,但有可能。
关于iphone - 我的 block 没有保留它的一些对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4587954/