为什么静态分析器不会检测带有块的循环引用?我记得当我保留我的代表而不是分配,预先阻止介绍时,它曾经这样做。我记得它用于绘制代码的漂亮小线条(我认为......)
如果我这样做,不使用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
现在,如果我知道这一点,而且我是一个愚蠢的人,那么为什么我的智能电脑不知道这很糟糕并警告我,我是愚蠢的?
必须有一个合理的原因,它无法检测到它,我想知道这是什么原因。
这个问题是关于铿锵声和静态分析的,请不要建议我如何修改循环引用 - 我知道如何做到这一点。
答案 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。