小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
今天继续了解一下切断target强持有的第三种方法
NSProxy虚基类
NSProxy的作用:
- OC不支持多继承,但是它基于运行时机制,可以通过NSProxy来实现伪多继承
- NSProxy和NSObject属于同一级别的类,也可以说是一个虚拟类,只实现了NSObject的协议部分
- NSProxy本质是一个消息转发封装的抽象类,类似一个代理人 可以通过继承NSProxy,并重写以下两个方法实现消息转发
- (void)forwardInvocation:(NSInvocation *)invocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;
NSProxy除了可以用于多继承,也可以作为切断强持有的中间人 打开LGProxy.h文件,写入以下代码:
#import <Foundation/Foundation.h>
@interface LGProxy : NSProxy
+ (instancetype)proxyWithTransformObject:(id)object;
@end
打开LGProxy.m文件,写入以下代码:
#import "LGProxy.h"
@interface LGProxy()
@property (nonatomic, weak) id object;
@end @implementation LGProxy
+ (instancetype)proxyWithTransformObject:(id)object{
LGProxy *proxy = [LGProxy alloc];
proxy.object = object;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
if (!self.object) {
NSLog(@"异常收集-stack");
return nil;
}
return [self.object methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation{
if (!self.object) {
NSLog(@"异常收集-stack");
return;
}
[invocation invokeWithTarget:self.object];
}
@end
LGProxy的调用代码:
- (void)viewDidLoad {
[super viewDidLoad];
self.proxy = [LGProxy proxyWithTransformObject:self];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self.proxy selector:@selector(fireHome) userInfo:nil repeats:YES];
}
- (void)fireHome{
num++;
NSLog(@"hello word - %d",num);
}
- (void)dealloc{
[self.timer invalidate];
self.timer = nil;
}
- LGProxy初始化方法,将传入的object赋值给弱引用对象
- 再UIViewController中,创建LGProxy对象proxy。创建NSTimer对象,将proxy传入target,避免NSTimer对ViewController强持有。
- 当NSTimer回调时,触发LGProxy的消息转发方法
- methodSignatureForSelector:设置方法签名
- forwardInvocation:自身不做业务处理,将消息转发给object
- 当页面退出时,ViewController可以正常释放
- 再dealloc中,对NSTimer进行释放。此时NSTimer对proxy的强持有接触,proxy也跟着释放