一、内容
- NSProxy 是什么?
- 消息转发机制
- NSProxy 和 NSObject 的比较
- 解决 CADisplayLink ,NSTimer强引用target引起的无法释放问题。
二、NSProxy 含义
NSProxy
是跟NSObject
一样的基类,都遵守<NSObject>
协议NSProxy
是一个抽象类,必须继承实例化其子类才能使用。NSProxy
从类名来看是代理类专门负责代理对象转发消息的。相比NSObject
类来说NSProxy
更轻量级,通过NSProxy
可以帮助Objective-C
间接的实现多重继承的功能。
三、消息转发机制
当程序运行时调用一个没有实现的方法,会采用三个消息转发步骤如果这三个步骤都不能成功那么此时程序会抛出一个异常。
1.添加方法到类对象,对于实例方法调用respondsToSelector:
,对于类方法调用resolveClassMethod:
。
+(BOOL)resolveClassMethod:(SEL)sel;
-(BOOL)respondsToSelector:(SEL)aSelector;
2.查找forwardingTargetForSelector:
方法,该方法返回一个新对象,如果返回nil那么将跳转到下一步骤。
-(id)forwardingTargetForSelector:(SEL)aSelector;
3.通过methodSignatureForSelector:
方法获取一个NSMethodSignature
类型的对象,调用forwardInvocation:
方法。改方法传入一个封装了NSMethodSignature
的NSInvocation
对象。然后该对象通过invakeWithTarget:
方法将消息转发给其它对象。
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)invocation;
四、 NSProxy 和 NSObject 的比较
- 使用 NSProxy 做消息转发 比 使用 NSObject 效率高。
当这两个类都没有执行消息转发时,会报什么样的错误?
- NSProxy 会直接报 methodSignatureForSelector 方法错误
- NSObject 会报 [NSObject timerTest] 没有找到 错误
他们两个的执行流程:
- 继承至 NSObject 的类:
- 先去类对象里面找 -> 父类的类对象找 -> 缓存中 -> 搜索
- 继承至 NSProxy 的类:
- 先会在本类中找,如果没有直接消息转发。不会去 类对象找,父类的类对象中找。
isKindOfClass 方法的比较:
执行结果: 1 ,0
解释:
1、 isKindOfClass
: 检查 左边 是否是 右边的 类型或 子类
2、为什么 proxy2
打印结果是0
?
- 这是因为
proxy
的类型是MJProxy1
类型,WYProxy1
类型 继承至NSObject
。 - 也就是说
proxy2
是继承至NSObject
。说明proxy2
是 普通的 OC 对象。 - 那么
isKindOfClass
就按照普通 OC 对象处理 。NSObject != viewController
类型 所以 打印为0
3、那为什么 proxy1
打印结果是1
?
- 因为
proxy1
的类型是WYProxy2
.WYProxy2
继承至NSProxy
. - 只要是继承至
NSProxy
,那么大部分就会进入消息转发阶段。 - 也就意味着,在 调用
isKindOfClass
的时候,也进入了消息转发。就会进入到methodSignatureForSelector
和forwardInvocation
这两个方法。 - 它的调用顺序就改成了
target
。也就是说先拿到[WYProxy proxyWithtarget: vc]
中的 vc . - 然后
[proxy1 isKindOfClass:[ViewController class]]
变成了[vc isKindOfClass:[ViewController class]];
五 、 解决 CADisplayLink ,NSTimer强引用target引起的无法释放问题。
参考 内存管理:CADisplayLink、NSTimer、NSProxy 使用注意