经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
[iOS]定时器NSTimer、CADisplayLink的内存管理
来源:cnblogs  作者:EverNight  时间:2021/6/15 9:09:10  对本文有异议

NSTimer、CADisplayLink会对target产生强引用,如果target同时对他们产生强引用,则会发生循环引用。

以NSTimer为例,解决循环引用的问题。

方法1:使用block

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. // Do any additional setup after loading the view.
  4. __weak typeof(self) weakself = self;
  5. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
  6. [weakself func];
  7. }];
  8. }
  9. - (void)func
  10. {
  11. NSLog(@"%s",__func__);
  12. }
  13. - (void)dealloc
  14. {
  15. NSLog(@"%s",__func__);
  16. [self.timer invalidate];
  17. }

方法2:使用NSObject作为中间对象

  1. Proxy1.h
  2. @interface Proxy1 : NSObject
  3. + (instancetype)initWithTarget:(id)target;
  4. @end
  1. Proxy1.m
  2. @interface Proxy1 ()
  3. @property (nonatomic,weak) id target;
  4. @end
  5.  
  6. @implementation Proxy1
  7. + (instancetype)initWithTarget:(id)target
  8. {
  9. Proxy1 *proxy = [[Proxy1 alloc] init];
  10. proxy.target = target;
  11. return proxy;
  12. }
  13. - (id)forwardingTargetForSelector:(SEL)aSelector
  14. {
  15. return self.target;
  16. }
  17. @end
  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. // Do any additional setup after loading the view.
  4. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[Proxy1 initWithTarget:self] selector:@selector(func) userInfo:nil repeats:YES];
  5. }
  6. - (void)func
  7. {
  8. NSLog(@"%s",__func__);
  9. }
  10. - (void)dealloc
  11. {
  12. NSLog(@"%s",__func__);
  13. [self.timer invalidate];
  14. }

方法3:使用NSProxy作为中间对象

  1. Proxy2.h
  2. @interface Proxy2 : NSProxy
  3. + (instancetype)initWithTarget:(id)target;
  4. @end
  1. Proxy2.m
  2. @interface Proxy2 ()
  3. @property (nonatomic,weak) id target;
  4. @end
  5.  
  6. @implementation Proxy2
  7. + (instancetype)initWithTarget:(id)target
  8. {
  9. Proxy2 *proxy = [Proxy2 alloc];
  10. proxy.target = target;
  11. return proxy;
  12. }
  13. - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
  14. {
  15. return [self.target methodSignatureForSelector:sel];
  16. }
  17. - (void)forwardInvocation:(NSInvocation *)invocation
  18. {
  19. [invocation invokeWithTarget:self.target];
  20. }
  21. @end
  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. // Do any additional setup after loading the view.
  4. self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[Proxy2 initWithTarget:self] selector:@selector(func) userInfo:nil repeats:YES];
  5. }
  6. - (void)func
  7. {
  8. NSLog(@"%s",__func__);
  9. }
  10. - (void)dealloc
  11. {
  12. NSLog(@"%s",__func__);
  13. [self.timer invalidate];
  14. }

方法3的优点:

执行效率高,无需执行父类的方法搜索过程,直接进行消息转发。

关于NSProxy补充:

通过调用isKindOfClass

  1. Proxy1 *proxy1 = [Proxy1 initWithTarget:self];
  2. Proxy2 *proxy2 = [Proxy2 initWithTarget:self];
  3. NSLog(@"%d",[proxy1 isKindOfClass:[ViewController class]]); // 0
  4. NSLog(@"%d",[proxy2 isKindOfClass:[ViewController class]]); // 1

proxy1为Proxy1类型,Proxy1继承自NSObject,可以正常处理isKindOfClass方法,所以判断结果为0.

proxy2为Proxy2类型,Proxy2继承自NSProxy,大部分方法会直接进入消息转发阶段,会改为使用target进行调用,所以判断结果为1.

通过观察NSProxy的源码发现,该方法直接进行了消息转发。

  1. /**
  2. * Calls the -forwardInvocation: method to determine if the 'real' object
  3. * referred to by the proxy is an instance of the specified class.
  4. * Returns the result.<br />
  5. * NB. The default operation of -forwardInvocation: is to raise an exception.
  6. */
  7. - (BOOL) isKindOfClass: (Class)aClass
  8. {
  9. NSMethodSignature *sig;
  10. NSInvocation *inv;
  11. BOOL ret;
  12. sig = [self methodSignatureForSelector: _cmd];
  13. inv = [NSInvocation invocationWithMethodSignature: sig];
  14. [inv setSelector: _cmd];
  15. [inv setArgument: &aClass atIndex: 2];
  16. [self forwardInvocation: inv];
  17. [inv getReturnValue: &ret];
  18. return ret;
  19. }

原文链接:http://www.cnblogs.com/EverNight/p/14876063.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号