使用块保留`self`循环

我担心这个问题非常基本,但我认为这与很多进入数据块的Objective-C程序员有关。

我听到的是,由于块捕获作为const副本在其中引用的局部变量self,因此如果要复制该块,则在块内使用可能会导致保留周期。因此,我们应该使用__block强制块直接处理self而不是复制它。

__block typeof(self) bself = self;[someObject messageWithBlock:^{ [bself doSomething]; }];

而不仅仅是

[someObject messageWithBlock:^{ [self doSomething]; }];

我想知道的是:如果这是真的,有没有办法可以避免丑陋(除了使用GC)?


函数式编程
浏览 547回答 3
3回答

德玛西亚99

严格来说,它是一个const副本的事实与这个问题无关。块将保留创建时捕获的任何obj-c值。恰好,const-copy问题的解决方法与保留问题的解决方法相同; 即,使用__block变量的存储类。无论如何,要回答你的问题,这里没有真正的选择。如果你正在设计自己的基于块的API,并且这样做是有意义的,你可以让块self作为参数传递in 的值。不幸的是,这对大多数API来说没有意义。请注意,引用ivar具有完全相同的问题。如果您需要在块中引用ivar,请使用属性或使用bself->ivar。附录:编译为ARC时,__block不再中断保留周期。如果您正在为ARC编译,则需要使用__weak或__unsafe_unretained替代。

回首忆惘然

这可能是显而易见的,但是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,从长远来看,混叠可能是最佳实践。
打开App,查看更多内容
随时随地看视频慕课网APP