- CADidsplayLink & NSTimer
这两种使用方式 定时器都会强引用target
, 从而造成self-> timer -> self
的循环引用
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(linktest)];
[self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
这里有的小伙伴可能也会使用 __weak typeof(self) weakSelf = self;
传递给target 但是这样也是不行的, 虽然传递的是weak后指向的弱指针,但是指向的还是target对象的地址,所以还是会产生强引用
self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(linktest) userInfo:nil repeats:YES];
- 解决方案
-
NSTimer
可以以block的形式使用,block
内部使用__weak弱引用self
即可
__weak typeof(self) weakSelf = self;
self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
[weakSelf linktest];
}];
中间对象
继承至
NSObject
的中间对象WTProxy 内部 弱引用一个 target对象
timer强引用
------> WTProxy弱引用
------>target
转发消息给target执行aSelector- (id)forwardingTargetForSelector:(SEL)aSelector
@interface WTProxy : NSObject
@property (nonatomic, weak) id target;
+ (WTProxy *)proxyWithTarget:(id)target;
@end
@implementation WTProxy
+ (WTProxy *)proxyWithTarget:(id)target
{
WTProxy *proxy = [WTProxy alloc];
proxy.target = target;
return proxy;
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.target;
}
@end
继承自
NSProxy
的中间对象
- timer
强引用
----> WTProxy1弱引用
----> target- 消息转发给target 进行方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
- 调用
- (void)forwardInvocation:(NSInvocation *)invocation
@interface WTProxy1 : NSProxy
@property (nonatomic, weak) id target;
+ (WTProxy1 *)proxyWithTarget:(id)target;
@end
@implementation WTProxy1
+ (WTProxy1 *)proxyWithTarget:(id)target
{
WTProxy1 *proxy = [WTProxy1 alloc];
proxy.target = target;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
[invocation invokeWithTarget:self.target];
}
NSObject和NSProxy作为中间对象 它们有什么区别
从上面的示例代码感觉 NSObject来做中间对象好像更加好一点才对啊. (因为只调用forwardingTargetForSelector一个方法
) 其实不是原因如下
- NSObject的中间对象, 它的方法转发流程是 先会通过
isa
指向的类对象, 从缓存、类、 父类、中进行方法查找
, 没有找到进行动态方法解析
, 如果没有解析, 才会进入消息转发
- NSProxy的中间对象, 是直接进入
消息转发
, 少了从父类进行方法查询(消息发送
),少了动态方法解析
这里两个阶段, 使用Target
将Selector
生成方法签NSMethodSignature
,然后forwardInvocation 调用方法,即可完成消息转发的流程, 效率比NSObject的会高很多.
网友评论