NSTimer
@property (nonatomic, strong) NSTimer *timer;
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerStartMethord) userInfo:nil repeats:YES];
}
- (void)timerTest{
NSLog(@"%s",__func__);
}
- (void)dealloc{
[self.timer invalidate];
}
上面这段代码控制器和定时器都是不会释放的。
原因:
-
在类拓展中控制器对当前的定时器进行了强引用,在控制器的viewDidLoad方法里面,timer的创建又对控制器进行的强引用(Target参数)。造成了循环应用。控制器和定时器都不会进行释放 。
image.png
解决方案:
- 将控制器对当前timer进行弱引用
@property (nonatomic, weak) NSTimer *timer;
image.png
虽然现在VC对timer进行了弱引用,但是VC和timer还是不能释放,因为runloop对timer进行强引用,timer对VC进行了强引用。

所以我们声明中间变量 HJProxy
@interface HJProxy : NSObject
@property (nonatomic, weak) id target;
+ (instancetype)proxyWithTarget:(id)target;
@end
+ (instancetype)proxyWithTarget:(id)target{
HJProxy *proxy = [[HJProxy alloc] init];
proxy.target = target;
return proxy;
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
return self.target;
}
//- (NSMethodSignature *)methodSignatureForSelectlor:(SEL)aSelector{
//
//}
//- (void)forwardInvocation:(NSInvocation *)anInvocation{
//
//}
///< 利用消息转发机制将消息转发出去
///< 1. 去方法列表中搜索方法(self super)
///< 2. 找不到进入动态方法解析阶段
///< 3. 动态方法解析找不到 就进入消息转发阶段
///< 4. 先调用forwardingTargetForSelector这个方法,
///< 如果这个方法你没有返回值的话,调用methodSignatureForSelector, 最后调用forwardInvocationl
所以我们调用timer 的方法就变成
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[HJProxy proxyWithTarget:self] selector:@selector(timerStartMethord) userInfo:nil repeats:YES];
}
这样就能像我上面展示的那个图一样,避免循环引用
3.中间变量改造 NSProxy
我们上面的中间变量是继承自NSObject,但是我们这里的中间变量将继承NSProxy
@interface HJProxyProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (nonatomic, weak) id target;
@end
///< NSProxy 本身就没有Init方法,所以直接调用alloc 分配内存就可以了
///< NSProxy 这个类存在的意义就是就来解决 代理行为 ,转发行为
+ (instancetype)proxyWithTarget:(id)target{
HJProxyProxy *proxy = [HJProxyProxy alloc];
proxy.target = target;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{ ///< 返回方法签名
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation{ ///< 调用
[invocation invokeWithTarget:self.target];
}
那这两个中间类的方法的区别在哪里
- NSProxy 比 NSObject 的效率高,因为 NSObject 里面进行的消息转发,自己类中没有方法的话,他会去父类中找,但是NSProxy他是一步到位,他自己类中如果没有方法,他是不需要去父 类中搜索方法的,
直接进入消息转发调用methodSignatureForSelector , 相当于节省了去父类搜索的这个流程。
网友评论