曾几何时,为了避免循环引用,都知道加__weak 和 __strong.
通常都喜欢配对来写如
__weak typeof(self) wself = self;
[xxxx founction:(^(){
__strong typeof(self) strong self = wself;
})];
但真的安全了吗?所谓的安全或不安全都是建立在一定的条件下的,只有碰到了,才能更深的去分晰。
上晰写法在 90%的情况下是没有啥问题的。 大家都这么用是不。那10%的出错概率是怎么样造成的。
文字看的累。看图。
从中可以看到跑来起来,的确crash了嘛。为啥呢?很多时候我们在block strong一个栈对象来防止外面的对象释放而带来的问题,但现在strong了,还是没有用。问题出在那了?可能细心的读者已经发现有点不太对了。
看下头文件
@interface MarketInsideSearchViewController ()<UITableViewDelegate,UITableViewDataSource,MarketSearchViewDelegate,SearchMarketInsideCellDelegate>{
NSString *_searchText;
}
对这里用的是成员变量,而不是属性访问。
好把这个改成属性如图:
继续上图来看看访问的效果.
同样是崩在了第三个日志,对成员变量的访问。而使用getter的访问却能正常?为什么?这个大家百度下关于成员函数和属性变量的相关区别。我个人认为使用属性访问安全是在于因为class free了。当空的实例在访问属性时其实是访问getter而此时isa指针去寻找相关的属性列表中Getter时是找不到的,所以不调用了。而使用-> 其实是直接来读取_searchText 所在的地址,而此地址却是个非法地址看(BAD_ACCESS),所以就报错了。
发现这个问题的起因:
是在处理项目的告警的时候:
利用编译器检测retain self cycle 引用圈. 在build settings中
implicit retain of 'self' within blocks 设为YES
Analyze During 'Build' 设为YES , 编译运行的时候也同步进行静态分析
当采用成员变量的声明时(非属性)
很多时候不小心以为这个写就可以避免循环引用。其实不然,这样同样会被隐式的使用了self.即,if那句等价于if (self->_searchText.length) 同样产行强引用。告警中说明了隐式引用,建议你进行显式调用。于是呼,不就是显示调用么,简单,就改成weakSelf->_searchText.length就完事了,这样又可以调用,又可以解除循环引用。哈哈。恭喜。object C 不允许weak对象直接访问成员变量(为什么不允许这个大家goolge吧,百度估计也没有人回答,找到后回复一个地址我好看下。暂时还没有去找。)
到此,出大招了,就是前面碰到crash 的 ,用__strong呀。不仅解决了循环引用,还解决了告警。一举两得。但这之后随即引入了一个非常隐秘的crash。
所以大家尽量使用属性的写法,而少用成员,如果要用,尽量不要在block中去访问。比如使用一个方法进行转换如上面可以尝试改成
- (NSInterger )getSearchTextLength
{
return _searchText.length;
}
然后用if (weakSelf getSearchTextLength) {}这样就可以巧妙的避开了block中直接访问变量了。