我担心这个问题非常基本,但我认为这与很多进入数据块的Objective-C程序员有关。我听到的是,由于块捕获作为const副本在其中引用的局部变量self,因此如果要复制该块,则在块内使用可能会导致保留周期。因此,我们应该使用__block强制块直接处理self而不是复制它。__block typeof(self) bself = self;[someObject messageWithBlock:^{ [bself doSomething]; }];而不仅仅是[someObject messageWithBlock:^{ [self doSomething]; }];我想知道的是:如果这是真的,有没有办法可以避免丑陋(除了使用GC)?
3 回答
德玛西亚99
TA贡献1770条经验 获得超3个赞
严格来说,它是一个const副本的事实与这个问题无关。块将保留创建时捕获的任何obj-c值。恰好,const-copy问题的解决方法与保留问题的解决方法相同; 即,使用__block
变量的存储类。
无论如何,要回答你的问题,这里没有真正的选择。如果你正在设计自己的基于块的API,并且这样做是有意义的,你可以让块self
作为参数传递in 的值。不幸的是,这对大多数API来说没有意义。
请注意,引用ivar具有完全相同的问题。如果您需要在块中引用ivar,请使用属性或使用bself->ivar
。
附录:编译为ARC时,__block
不再中断保留周期。如果您正在为ARC编译,则需要使用__weak
或__unsafe_unretained
替代。
回首忆惘然
TA贡献1847条经验 获得超11个赞
这可能是显而易见的,但是self
当你知道你会得到一个保留周期时,你只需要做丑陋的别名。如果块只是一次性的东西,那么我认为你可以安全地忽略保留self
。例如,当您将块作为回调接口时,不好的情况就是如此。像这儿:
typedef void (^BufferCallback)(FullBuffer* buffer);@interface AudioProcessor : NSObject {…}@property(copy) BufferCallback bufferHandler;@end@implementation AudioProcessor- (id) init { … [self setBufferCallback:^(FullBuffer* buffer) { [self whatever]; }]; …}
这里的API没有多大意义,但是在与超类通信时也是有意义的。我们保留缓冲区处理程序,缓冲区处理程序保留了我们。比较这样的事情:
typedef void (^Callback)(void);@interface VideoEncoder : NSObject {…}- (void) encodeVideoAndCall: (Callback) block;@end@interface Foo : NSObject {…}@property(retain) VideoEncoder *encoder;@end@implementation Foo- (void) somewhere { [encoder encodeVideoAndCall:^{ [self doSomething]; }];}
在这些情况下,我不做self
别名。你确实得到一个保留周期,但是操作是短暂的,并且块最终会从内存中断开,从而打破周期。但是我对块的体验非常小self
,从长远来看,混叠可能是最佳实践。
- 3 回答
- 0 关注
- 546 浏览
添加回答
举报
0/150
提交
取消