block为用了__weak 和__strong 就一定是安全的?

曾几何时,为了避免循环引用,都知道加__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中直接访问变量了。



猜你喜欢

转载自blog.csdn.net/fengsh998/article/details/79769829