NSProxy 设计消息转发

  • 2019 年 10 月 8 日
  • 筆記

首先,了解下NSTimer的循环引用

@interface ViewController ()  @property (nonatomic, strong) NSTimer *timer;  @end    @implementation ViewController  - (void)viewDidLoad {      [super viewDidLoad];      self.timer = [NSTimer scheduledTimerWithTimeInterval:1  			                  													target:self                                                  selector:@selector(testForTimer)                                                  userInfo:nil                                                   repeats:YES];  }    - (void)testForTimer {      NSLog(@"%s",__func__);  }  @end

循环引用:

mage

  • 可能有的人说用__weak 来修饰self 从而达到target指向ViewController是弱引用的效果。
  • 不行! 因为weak 也是把地址赋值给targettarget还是强引用viewController地址。我们用的weak是处理block的循环引用,block中会把__weak修饰的对象 描述为弱引用

关于SRProxy

@interface SRProxy : NSProxy  @property (nonatomic, weak) id target;  + (instancetype)proxyWithTarget:(id)target;  @end
@implementation SRProxy  + (instancetype)proxyWithTarget:(id)target {      SRProxy *proxy = [SRProxy alloc];      proxy.target = target;      return proxy;  }    - (id)forwardingTargetForSelector:(SEL)aSelector {      if (self.target) {          return self.target;      }      return self;  }    -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {      return [self.target  methodSignatureForSelector:aSelector];  }    - (void)forwardInvocation:(NSInvocation *)invocation {      [invocation invokeWithTarget:self.target];  }  @end

关于解决方式

self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[SRProxy proxyWithTarget:self] selector:@selector(testForTimer) userInfo:nil repeats:YES];

解释NSProxy

结构
@interface NSProxy <NSObject> {      Class	isa;  }

NSProxy为基类,和NSObject同级, 专门处理这种代理实现事件。

SRProxy继承于NSProxy 如果继承NSObject 也可以实现功能。

NSProxy 和NSObject比较

继承于NSProxy的类 找实现方法的时候 只会找当前类是否实现 而不找super,如果没找到直接进入消息动态解析,以及消息转发机制。比继承NSObject的类少了找super,从而效率更高。

实验1

如果把SRProxy中的消息转发机制去掉 看一下错误信息

继承NSProxy
继承NSObject

NSProxy没有init方法 只要alloc 既可

实验2

当我们继承于NSProxy 在上述ViewDidLoad 中打印此代码 结果为

 NSLog(@"isKindOfClass  == %d",[[SRProxy proxyWithTarget:self] isKindOfClass:[self class]]);
解释

调用isKindOfClass 进行消息转发 走的是下面的方法

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {      return [self.target  methodSignatureForSelector:aSelector];  }
- (void)forwardInvocation:(NSInvocation *)invocation {  	[invocation invokeWithTarget:self.target];  }

实际调用的是self.target 去执行objc_msgSend(self.target,SEL) 所以为1

isKindOfClass 为1