为了账号安全,请及时绑定邮箱和手机立即绑定

使用块保留`self`循环

使用块保留`self`循环

函数式编程 2019-09-19 08:44:26
我担心这个问题非常基本,但我认为这与很多进入数据块的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替代。


查看完整回答
反对 回复 2019-09-19
?
回首忆惘然

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,从长远来看,混叠可能是最佳实践。


查看完整回答
反对 回复 2019-09-19
  • 3 回答
  • 0 关注
  • 546 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信