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];
    }
  • 相关阅读:
    ruby 二进制转十进制 Integer("0b101") = 5
    开始菜单和我的文档的我的图片及我的音乐变成 my pictrues 正常图标了
    ruby watir 莫名其妙的错误
    Excel SaveAS是去掉提示框
    apache && jboss安装
    ruby require include的区别
    ruby控制鼠标
    This error is raised because the column 'type' is reserved for storing the class in case of inheritance
    用正则表达式限制文本框只能输入数字,小数点,英文字母,汉字等各类代码
    ASP.NET 如何动态修改 Header 属性如添加 Meta 标签 keywords description!
  • 原文地址:https://www.cnblogs.com/HJQ2016/p/5928801.html
Copyright © 2011-2022 走看看