-
友情提示:点击查看本文所涉及的demo代码
导语
代理即是代表授权方处理事务(From Wikipedia)。
思考一下我们生活中什么时候会用到代理呢?
1 | 租房、买房时,我们需要一位中介帮我们联系房东,处理手续上的事情,降低我们和房东的沟通成本。 |
所以可以理解为中介帮我们解决两个层面上的问题:
- 减少互相依赖的问题
- 减少做重复的事情
所以从本质上来说,Proxy体现的还是”中间层”的设计思想,具体应用于”消息转发”的业务场景。
循环引用
在讲述今天这个Demo前,我们先回想一下之前我们接触过的Proxy的应用场景,我想你脑海中肯定第一时间浮现出:使用Proxy解决NSTimer循环引用的问题。
所以我们首先聊一聊 Proxy 使用最刚需的 「解决循环引用」的场景。
循环引用是怎么产生的
下图是内存正常回收的过程:
下面是产生循环引用导致内存泄漏的过程:
验证是否产生循环引用的最佳方式就是判断是否产生了一个引用环。
NSTimer 循环引用问题
NSTimer 问题最有趣的点是,网上关于 NSTImer 为什么会导致循环引用的解释 80%都是不清晰的,比如这样一个最普遍的说法:
这样的说法就好似有人问小明:”NSTimer为什么会导致循环引用?”
小明却回答:”NSTimer会导致循环引用”。
上演了一出”搁着搁着呢”的好戏😂。
循环引用一定是 ViewController 和 NSTimer 相互强引用,但为什么 NSTimer addTarget 会导致循环引用,但平时我们使用的 UIButton addTarget却不会导致循环引用呢?
回答清楚这个问题,才算是说清楚了”NSTimer为什么会导致循环引用”。
其实解答这个问题也很简单😂 我们查一下大苹果提供的文档说明,
对于 UIControl :
The control does not retain the object in the target parameter. It is your responsibility to maintain a strong reference to the target object while it is attached to a control.
翻译成中文含义就是: 控件不保留目标参数中的对象。在目标对象附加到控件时,维护对目标对象的强引用是您的责任
对于 NSTimer 说明如下:
The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated.
中文含义是:当定时器触发时,要发送由aSelector指定的消息到的对象。计时器维护对该对象的强引用,直到它(计时器)失效。
这样一看就明白多了,之所以 NSTimer 会导致强引用,但 UIControl 不会导致强引用,是大苹果的feature,达到了真正的类比深入的效果。
破解 NSTimer 循环引用的方法我们都很熟练了,我们贴一张图即可:
简单小Demo
开发时我们经常会写出这样的代码:
1 | - (UIButton *)closeBtn { |
消息转发流程是: click button -> button selector -> delegate method,
而实际上我们只需要: click button -> delegate method
我们想省去 button selector 这个步骤,怎么做呢?
既然是消息转发的事情,那就采用 Proxy 的思路:
1 | #import "DelegateMethodProxy.h" |
优化 UIButton 的调用方法:
1 | - (UIButton *)closeBtn { |
如此一来,业务层就直接实现了 click button -> delegate method 的调用链路。