来自块文档:
在引用计数环境中,通过
当您引用时默认
块内的 Objective-C 对象,它
被保留。即使您
只需引用实例变量
对象的。
我正在尝试实现一个完成处理程序模式,其中在执行工作之前向对象提供一个块,并在执行工作之后由接收器执行该块。由于我是一个良好的内存公民,因此该块应该拥有它在完成处理程序中引用的对象,然后当该块超出范围时它们将被释放。我知道,我必须复制该块以将其移动到堆,因为该块将在声明它的堆栈范围内生存。
然而,我的一个对象意外地被释放。经过一番尝试后,发现当块复制到堆时,某些对象不会被保留,而其他对象则会被保留。我不确定我做错了什么。这是我可以生成的最小测试用例:
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:@"[email protected]",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]);
我希望两个对象在某个时刻被块保留,并且我当然希望它们的保留计数相同。相反,我得到以下输出:
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
不会被保留,并且会在块运行之前被释放,从而导致崩溃。
From the Blocks documentation:
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.
I am trying to implement a completion handler pattern, where a block is given to an object before the work is performed and the block is executed by the receiver after the work is performed. Since I am being a good memory citizen, the block should own the objects it references in the completion handler and then they will be released when the block goes out of scope. I know enough to know that I must copy
the block to move it to the heap since the block will survive the stack scope in which it was declared.
However, one of my objects is getting deallocated unexpectedly. After some playing around, it appears that certain objects are not retained when the block is copied to the heap, while other objects are. I am not sure what I am doing wrong. Here's the smallest test case I can produce:
typedef void (^ActionBlock)(UIView*);
In the scope of some method:
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:@"[email protected]",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]);
I expect both objects to be retained by the block at some point, and I certainly expect their retain counts to be identical. Instead, I get this output:
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
(subclass of NSObject
) is getting retained properly and will not go out of scope. However mailViewController
is not retained and will be deallocated before the block is run, causing a crash.
发布评论
评论(3)
不要使用-retainCount。
对象的绝对保留计数是没有意义的。
您应该调用
release
的次数与导致对象被保留的次数完全相同。不能少(除非你喜欢泄漏),当然也不能多(除非你喜欢崩溃)。请参阅内存管理指南了解完整详细信息。
(抄袭@bbum的答案之一)
至于你的问题:
你真的在观察崩溃吗?或者你只是盲目地从臀部射击并认为它可能会崩溃?
从您发布的代码来看,
mailViewController
似乎是一个实例变量,在这种情况下,该块将保留self
而不是实例变量。由于您自动释放
实例变量,它会被NSAutoreleasePool
清理,就像您所期望的那样。总之:
-retainCount
。autorelease
您希望在运行循环之外存在的实例变量。编辑更多说明:
创建块时将发生以下情况:
self->mailViewController
和o
。self->mailViewController
是结构体 (self
) 的成员,因此不会直接保留。相反,保留self
。o
是一个局部变量。保留它。这是正确的行为。至于您的代码...
o
是使用 +0 保留计数创建的self->mailViewController
是使用 +0 保留计数创建的myBlock
创建时保留计数为 +0。o
现在有 +1 RC,self
也是如此。self->mailViewController
仍然有 +0 RCmyBlock
已复制 => +1 保留计数快进到该运行循环周期的末尾。
self->mailViewController
。 self->mailViewController 现在指向已释放的内存,本质上是垃圾。快进到执行
myBlock
时的某个未来点,myBlock
尝试调用self->mailViewController
上的方法。但是,self->mailViewController
不再指向有效的对象,并且您的应用程序崩溃了。但是,如果
mailViewController
不是实例变量,那么我们需要查看更多代码。我认为您所看到的行为不太可能是块运行时的问题,但有可能。Do not use -retainCount.
The absolute retain count of an object is meaningless.
You should call
release
exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).See the Memory Management Guidelines for full details.
(cribbed from one of @bbum's answers)
As for your question:
Are you actually observing a crash? Or are you just shooting blindly from the hip and thinking that it might crash?
From the code you posted, it would appear that
mailViewController
is an instance variable, in which case the block would be retainingself
instead of the instance variable. And since youautoreleased
your instance variable, it's getting cleaned up by anNSAutoreleasePool
just like you'd expect.So in summary:
-retainCount
.autorelease
instance variables that you want to exist beyond this turn of the run loop.edit A bit more clarification:
Here's what's going to happen when your block is created:
self->mailViewController
ando
.self->mailViewController
is a member of a struct (self
), so it is not retained directly. Retainself
instead.o
is a local variable. Retain it.This is proper behavior. As for your code...
o
is created with a +0 retain countself->mailViewController
is created with a +0 retain countmyBlock
is created with a +0 retain count.o
now has a +1 RC, as doesself
.self->mailViewController
still has a +0 RCmyBlock
is copied => +1 retain countFast forward to the end of this run loop cycle.
self->mailViewController
.self->mailViewController
now points to deallocated memory, and is essentially garbage.Fast forward to some future point when
myBlock
is executedmyBlock
attempts to invoke a method onself->mailViewController
. However,self->mailViewController
no longer points to a valid object, and your app crashes.However, if
mailViewController
is not an instance variable, then we need to see more code. I think it'd be highly unlikely that the behavior you're seeing is a problem with the blocks runtime, but it is possible.文档不再这么说了。现在它正确地说:
The documentation no longer says that. It now correctly says:
由于“mailViewController”是当前类实例的成员,因此该块实际上在这里保留“self”。
As the "mailViewController" is a member of your current class instance, so the block actually retain "self" here.