Objective-C和clang中的循环引用

时间:2015-10-21 20:32:36

标签: objective-c circular-reference

为什么静态分析器不会检测带有块的循环引用?我记得当我保留我的代表而不是分配,预先阻止介绍时,它曾经这样做。我记得它用于绘制代码的漂亮小线条(我认为......)

如果我这样做,不使用weakSelf,我知道我会得到一个循环引用。

// Note 1: myObject is 'retained' by self. 
// Note 2: myObject retains the block for the future

[self.myObject registerBlockOfCodeForFutureExectution:^{
    [self doSomething];
}];

Sample Project Exploiting Issue

现在,如果我知道这一点,而且我是一个愚蠢的人,那么为什么我的智能电脑不知道这很糟糕并警告我,我是愚蠢的?

必须有一个合理的原因,它无法检测到它,我想知道这是什么原因。

这个问题是关于铿锵声和静态分析的,请不要建议我如何修改循环引用 - 我知道如何做到这一点。

2 个答案:

答案 0 :(得分:2)

如果在块内使用self,则不会自动表示您获得保留周期。只有当块的生命周期取决于self对象的生命周期时,才会获得保留周期。如果self具有对myObject的强引用,或者某些更复杂的依赖关系也是可能的,则可能就是这种情况(我认为它确实'保存'阻止传递给方法,所以你已经有很强的参考价值了。)

因此,要在您的示例中保留循环,您需要满足以下两个条件(它们都不是您发布的代码),编译器需要知道它们: 1. myObject的生命周期与自我联系在一起 - 让我们假设自己有很强的参考价值 2. saveThisBlockInMyObject:保留传递给它的块

我做了一个小样本,它给出了关于捕获self的编译器警告 - 解决第一点我将myObject声明为某个类的强属性:

@property (strong) MyTestClass* myObj;
...
self.myObj = [MyTestClass new];

对于第二点,我找不到指定该方法保留其参数的方法(返回值为source annotations,但方法参数没有相关注释)。但是您将块声明为测试类的强属性,然后编译器很乐意警告您可能的保留周期:

typedef void (^MyVoidBlock)();
// MyTestClass
@property (nonatomic, copy) MyVoidBlock voidBlock;

self.voidBlock = ^{
    [self doSomething]; // Warning!
};

希望有道理:)

答案 1 :(得分:1)

发布到github的代码会导致保留周期。

当前的github代码:

@interface MyObject ()
@property (nonatomic, copy) dispatch_block_t codeToRunInFuture;
@end

@implementation MyObject

- (void) registerBlockForFuture:(dispatch_block_t)block {
    self.codeToRunInFuture = block;
}

// Call in ViewController
self.myObject = [MyObject.alloc init];
[self.myObject registerBlockForFuture:^{
    [self runThisInFuture];
}];

我可以看到这很难被捕获的地方,因为分析器无法知道block可能是什么,因此无法判断自我引用是强还是弱。它必须检查调用registerBlockForFuture:的所有实例和每种情况下的block

答案可能是向Apple提交bugreport