zoukankan      html  css  js  c++  java
  • 第四十三篇、利用NSProxy解决NSTimer内存泄漏问题

    问题描述:
      用NSTimer来实现每隔一定时间执行制定的任务,例如最常见的广告轮播图。如果我们在 timerWithTimeInterval:1 target:self 中指定target为当前控制器,控制器则会被timer强引用,而控制器对timer也是强引用的。一般,我们终止定时器往往在界面销毁时,即dealloc方法中写 [_timer invalidate];。基于上面的分析,由于循环引用的存在,控制器永远也不会走dealloc方法,定时器会一直执行方法,造成内存泄露。

    解决方案:

      利用消息转发来断开NSTimer对象与视图之间的引用关系。初始化NSTimer时把触发事件的target替换成一个单独的对象,然后这个对象中NSTimer的SEL方法触发时让这个方法在当前的视图self中实现。

    背景知识:
      NSProxy:NSProxy 是一个抽象类,它接收到任何自己没有定义的方法他都会产生一个异常,所以一个实际的子类必须提供一个初始化方法或者创建方法,并且重载forwardInvocation:方法和methodSignatureForSelector:方法来处理自己没有实现的消息。
    从类名来看是代理类,专门负责代理对象转发消息的。相比NSObject类来说NSProxy更轻量级,通过NSProxy可以帮助Objective-C间接的实现多重继承的功能。

    代码:

    #import <Foundation/Foundation.h>
    
    @interface XZHProxy : NSProxy
    /**
     *  代理的对象
     */
    @property (nonatomic,weak)id obj;
    @end
    #import "XZHProxy.h"
    
    @implementation XZHProxy
    
    /**
     这个函数让重载方有机会抛出一个函数的签名,再由后面的forwardInvocation:去执行
        为给定消息提供参数类型信息
     */
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
        NSMethodSignature *sig = nil;
        sig = [self.obj methodSignatureForSelector:aSelector];
        return sig;
    }
    
    /**
     *  NSInvocation封装了NSMethodSignature,通过invokeWithTarget方法将消息转发给其他对象.这里转发给控制器执行。
     */
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
        [anInvocation invokeWithTarget:self.obj];
    }
    @end
    #import "ViewController.h"
    #import "XZHProxy.h"
    @interface ViewController ()
    /**
     *代理
     */
    @property (nonatomic,strong)XZHProxy *proxy;
    
    /**
     *  定时器
     */
    @property (nonatomic,strong)NSTimer *timer;
    
    /**
     *  计数
     */
    @property (nonatomic,assign)NSInteger count;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        self.proxy = [XZHProxy alloc];
        //作为当前控制器的代理
        self.proxy.obj = self;
        //target为代理
        self.timer = [NSTimer timerWithTimeInterval:1 target:self.proxy selector:@selector(timerEvent) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    }
    
    - (void)timerEvent{
        NSLog(@"%zd",self.count++);
    }
    
    - (void)dealloc{
        NSLog(@"----dealloc");
        //释放计时器
        [self.timer invalidate];
    }
  • 相关阅读:
    107. Binary Tree Level Order Traversal II
    108. Convert Sorted Array to Binary Search Tree
    111. Minimum Depth of Binary Tree
    49. Group Anagrams
    使用MALTAB标定实践记录
    442. Find All Duplicates in an Array
    522. Longest Uncommon Subsequence II
    354. Russian Doll Envelopes
    opencv 小任务3 灰度直方图
    opencv 小任务2 灰度
  • 原文地址:https://www.cnblogs.com/HJQ2016/p/5928801.html
Copyright © 2011-2022 走看看