NSProxy

作用一: 代理
想要拦截自定义CPTabBarController(UITabBarController子类)中tabbar的点击事件,最简单的就是直接设置自己为自己的代理self.delegate=self,再实现代理方法tabBarController:shouldSelectViewController。这样设置代理方法一看就不爽,寻求此类事件的解决方法。
NSProxy是专门为消息转发而设计的抽象类,稍微设计下就可以达到此目的。

@interface CPWeakProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@end

#import "CPWeakProxy.h"
@implementation CPWeakProxy{
    __weak id _target;
}

- (instancetype)initWithTarget:(id)target {
    _target = target;
    return self;
}

+ (instancetype)proxyWithTarget:(id)target {
    return [[CPWeakProxy alloc] initWithTarget:target];
}

- (id)forwardingTargetForSelector:(SEL)selector {
    return _target;
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    return [_target respondsToSelector:aSelector];
}
@end

使用时在CPTabBarController的viewDidLoad方法中

    _proxy = [CPWeakProxy proxyWithTarget:self];
    self.delegate = _proxy;

这里必须将CPWeakProxy对象设置为控制器的属性强引用避免释放。
这里要注意的是CPWeakProxy对象必须实现respondsToSelector方法,因为UITabBarController的实现中肯定有诸如下面的代码

- (void)tabbarDidSelect{ // tabbarItem被点击时调用
    if (self.delegate && [self.delegate respondsToSelector:@selector(xxx)]) {
        [self.delegate xxx];
    }
}

CPWeakProxy是一个抽象类,respondsToSelector并未有默认实现,需要自行实现,否则会找不到方法崩溃。
tabbaritem点击时,调用代理CPWeakProxy的xxx方法,肯定找不到,触发消息转发进入CPWeakProxy的forwardingTargetForSelector方法,返回_target(就是我们自己写的CPTabBarController),调用回控制器中实现的代理方法,解决问题。

作用二:NSTimer的target
NSProxy还可以用来转发NSTimer的消息,避免NSTimer强引用控制器无法销毁。常规使用如下

 [NSTimer scheduledTimerWithTimeInterval:1 target:[CPWeakProxy proxyWithTarget:self] selector:@selector(xxx) userInfo:nil repeats:YES];

用上面方法后控制器能正常释放,但是程序崩溃了。。。

追查原因,是NSTimer会使CPWeakProxy对象无法释放,控制器销毁时没有销毁NSTimer,定时器继续回调CPWeakProxy的xxx方法,而消息转发方法forwardingTargetForSelector返回nil,转发失败程序崩溃。
结论,在控制器中NSTimer使用CPWeakProxy转发消息可以避免控制器无法销毁,但是控制器销毁时必须手动销毁定时器来保证CPWeakProxy对象正常释放。

设计的转发类继承自NSProxy而不是NSObject,是因为给NSProxy发送消息时只会在当前类中查找方法,一旦找不到就执行消息转发操作,相比NSObject少去了递归父类查找方法等流程,效率更高

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,776评论 0 9
  • 一、深复制和浅复制的区别? 1、浅复制:只是复制了指向对象的指针,即两个指针指向同一块内存单元!而不复制指向对象的...
    iOS_Alex阅读 1,424评论 1 27
  • 37.cocoa内存管理规则 1)当你使用new,alloc或copy方法创建一个对象时,该对象的保留计数器值为1...
    如风家的秘密阅读 893评论 0 4
  • 文/Jack_lin(简书作者)原文链接:http://www.jianshu.com/p/5d2163640e2...
    笔笔请求阅读 565评论 0 0
  • 序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了。今年,找过工作人可能会更深刻地体会到今年的就...
    独酌丿红颜阅读 2,404评论 18 60