[iOS]定时器NSTimer、CADisplayLink的内存管理
2021/6/12 8:36:45
本文主要是介绍[iOS]定时器NSTimer、CADisplayLink的内存管理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
NSTimer、CADisplayLink会对target产生强引用,如果target同时对他们产生强引用,则会发生循环引用。
以NSTimer为例,解决循环引用的问题。
方法1:使用block
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. __weak typeof(self) weakself = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) { [weakself func]; }]; } - (void)func { NSLog(@"%s",__func__); } - (void)dealloc { NSLog(@"%s",__func__); [self.timer invalidate]; }
方法2:使用NSObject作为中间对象
Proxy1.h @interface Proxy1 : NSObject + (instancetype)initWithTarget:(id)target; @end
Proxy1.m @interface Proxy1 () @property (nonatomic,weak) id target; @end @implementation Proxy1 + (instancetype)initWithTarget:(id)target { Proxy1 *proxy = [[Proxy1 alloc] init]; proxy.target = target; return proxy; } - (id)forwardingTargetForSelector:(SEL)aSelector { return self.target; } @end
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[Proxy1 initWithTarget:self] selector:@selector(func) userInfo:nil repeats:YES]; } - (void)func { NSLog(@"%s",__func__); } - (void)dealloc { NSLog(@"%s",__func__); [self.timer invalidate]; }
方法3:使用NSProxy作为中间对象
Proxy2.h @interface Proxy2 : NSProxy + (instancetype)initWithTarget:(id)target; @end
Proxy2.m @interface Proxy2 () @property (nonatomic,weak) id target; @end @implementation Proxy2 + (instancetype)initWithTarget:(id)target { Proxy2 *proxy = [Proxy2 alloc]; proxy.target = target; return proxy; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { return [self.target methodSignatureForSelector:sel]; } - (void)forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.target]; } @end
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[Proxy2 initWithTarget:self] selector:@selector(func) userInfo:nil repeats:YES]; } - (void)func { NSLog(@"%s",__func__); } - (void)dealloc { NSLog(@"%s",__func__); [self.timer invalidate]; }
方法3的优点:
执行效率高,无需执行父类的方法搜索过程,直接进行消息转发。
关于NSProxy补充:
通过调用isKindOfClass
Proxy1 *proxy1 = [Proxy1 initWithTarget:self]; Proxy2 *proxy2 = [Proxy2 initWithTarget:self]; NSLog(@"%d",[proxy1 isKindOfClass:[ViewController class]]); // 0 NSLog(@"%d",[proxy2 isKindOfClass:[ViewController class]]); // 1
proxy1为Proxy1类型,Proxy1继承自NSObject,可以正常处理isKindOfClass方法,所以判断结果为0.
proxy2为Proxy2类型,Proxy2继承自NSProxy,大部分方法会直接进入消息转发阶段,会改为使用target进行调用,所以判断结果为1.
通过观察NSProxy的源码发现,该方法直接进行了消息转发。
/** * Calls the -forwardInvocation: method to determine if the 'real' object * referred to by the proxy is an instance of the specified class. * Returns the result.<br /> * NB. The default operation of -forwardInvocation: is to raise an exception. */ - (BOOL) isKindOfClass: (Class)aClass { NSMethodSignature *sig; NSInvocation *inv; BOOL ret; sig = [self methodSignatureForSelector: _cmd]; inv = [NSInvocation invocationWithMethodSignature: sig]; [inv setSelector: _cmd]; [inv setArgument: &aClass atIndex: 2]; [self forwardInvocation: inv]; [inv getReturnValue: &ret]; return ret; }
这篇关于[iOS]定时器NSTimer、CADisplayLink的内存管理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-09-21拼接的xml报文,尖括号都被转移成了< 是什么原因-icode9专业技术文章分享
- 2024-09-21Svg Sprite Icon教程:从入门到实践
- 2024-09-21Svg Sprite Icon实战:从入门到上手
- 2024-09-20构建一个多PDF RAG聊天机器人:使用Langchain和Streamlit及代码
- 2024-09-20whatsapp webhook 回调的签名验证偶尔会失败是什么原因-icode9专业技术文章分享
- 2024-09-19Excel数据导出课程:初学者必备教程
- 2024-09-19Excel数据导入课程:新手入门指南
- 2024-09-19RBAC的权限管理入门教程
- 2024-09-19如何使用Svg Sprite Icon制作图标
- 2024-09-19uniapp 如何实现点赞后全局更新数据-icode9专业技术文章分享