众所周知,Block会对其中使用的对象进行强引用,但如果要在Block中要实现弹出ActionSheet的操作,又会有哪些问题呢?
换句话说,当有点像代理的Block遇上真正的代理方法——ActionSheet的点击事件,又会不会产生冲突呢?
1 问题描述
页面是一个TableViewController
,由继承自UITableViewCell
的不同类作为每个Cell的类,而Cell中的各种元素都交给了模型管理,也包括点击Cell触发的事件,代码如下:
1 | - (void)addCellGroup |
机智的我一看到Block中用到了self.view
就意识到这是一个循环引用问题,将会导致页面无法release,于是赶紧在Block外面声明了一个__weak
弱指针变量。但是感觉还是有些不对劲:ActionSheet作为Block的内部成员变量,能触发下面的按钮点击事件吗?
先运行试试。。。
为什么刚跳过去就又跳了回来,可是这段跳转控制器的代码明明是没问题的啊,难道是因为跳转之后Block被回收导致代理中声明的OALoginViewController
被同时Release了?可是这个控制器明明已经被window强引用了啊?
2 分析
于是我决定将ActionSheet对象的声明放到Block的外面,循环引用什么的先扔到一边吧,然而问题依旧。我决定仔细分析一下引用关系:
当页面跳转之后,虽然Block引用着ActionSheet,但由于ActionSheet本身是局部变量,会解除self.view
对它的引用,所以当Block被self解除引用时,Block和ActionSheet同时Release了,而此时OALoginViewController
被window引用,所以并不会被Release。
3 解决
所以问题一定出在ActionSheet的点击事件上,我尝试把页面的跳转方式改为modal,发现页面跳转正常了。但这不是我想要的,因为modal并不会释放原控制器。于是我又把点击事件里的方法剪切到actionSheet:didDismissWithButtonIndex:
方法,代码如下。
1 | - (void)addCellGroup |
4 结论
我认为是由于ActionSheet是modal方式覆盖到view上的,而当点击按钮,ActionSheet要消失却在当前Window找不到自身时,就会跳回原来的控制器,所以跳转必须在ActionSheet消失之后进行。
另外原页面的Dealloc方法会在跳转后调用,也达到了释放原页面的目的。
5 后记
本着“不作会死”的态度-_-|||,我又把ActionSheet的声明移到了Block里面,页面跳转还是正常的,但跳转之后原页面没有Release!!!
这又是为什么呢?我的猜测是当执行完Block本应被Release,但ActionSheet被self.view强引用,而ActionSheet与Block互相引用,最终导致页面无法被释放。
这个猜测未经证实,待我找到ARC下查看对象引用计数的方法再回来填坑