块内存管理

3

在这个苹果参考文献中,有一个关于objective-c中Blocks对象的概念性概述:

http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Blocks.pdf

然而,它并没有真正解释我和其他人可能关心的两个问题。第一个问题是:我可以将nil赋值给Block引用吗?还是应该使用NULL?或者两者都不能使用?

第二个问题涉及内存管理领域。例如,我声明了一个在堆栈上创建块对象的方法。

-(void)makeTheClass
{
    TheClass *object = [[TheClass alloc] init];

    object.blockReference = ^(void) { return nil; } 
}

这个对象是在某个作用域内创建的,在离开该作用域后将会销毁。但TheClass对象实际上将存储对这个(即将销毁的)块的引用:

typedef id (^WeirdBlockType)(void);

@interface TheClass {
    WeirdBlockType blockReference;   
}

如何为这样的块声明类属性? 这两者有什么区别:

@property (nonatomic, retain) WeirdBlockType blockReference;
@property (nonatomic, copy)   WeirdBlockType blockReference; 

在苹果文档中明确指出,块复制会将块移动到堆上。但如果我只是保留它呢?当它超出makeTheClass方法的范围时,它会被销毁吗?

2个回答

2
我已经找到了解决方案。感谢Gojan的回答,但他在一个地方实际上是错误的:
Wevah是正确的。在块上保留没有任何效果,直到它完全移动到堆上,只有Block_copy才能完成这样的任务。
也许块不是唯一的不能在栈上保留的对象;但是当你通过默认方式在堆上创建(alloc和init)任何NSObject子类实例时,默认情况下你不需要担心 - retain像往常一样工作。块对象默认情况下在堆栈上创建,这就是为什么它们的工作有点出人意料。
感谢大家!

我仍在努力理解这个问题,但我认为“在块上保留[literal]没有效果”这句话并不完全正确:它确实会增加块的保留计数,对吧?然而,它仍然会在堆栈上,所以我想那确实没什么用,因为一旦我们离开堆栈帧,它就会被丢弃。我可能已经自己解决了疑问 :) 只是想知道这是否有意义。无论如何,谢谢。 - ettore

0
我可以将nil分配给Block引用吗?还是应该使用NULL?
nil可以理解为“空的id类型”,而NULL被定义为((void *)0)。这里的区别在于上下文。如果您正在使用基于NSObject的对象,则应使用nil。
在块的情况下,您应该使用nil,因为您可以像处理NSObject一样与块交互(可以保留它,释放它等)。但是,如果您使用NULL,它也应该可以工作。

How do I declare a class property for such a block? What's the difference between these two:

@property (nonatomic, retain) WeirdBlockType blockReference;
@property (nonatomic, copy)   WeirdBlockType blockReference; 

?

文档中说:
如果您正在使用Objective-C,您可以发送块复制、保留和释放(以及自动释放)消息。
因此,两个声明都是有效的,但如果您问我,我更喜欢保留而不是复制。
总之:
块被视为在定义和实例化同时(运行时)定义的对象,因此在获得持久引用后,您可以像处理任何其他对象一样处理该引用。

6
如果你想让一个代码块在声明它的范围之外继续存在,你就必须复制它。 - Wevah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接