文档章节

使用NSTimer出现的问题

hell03W
 hell03W
发布于 2016/03/24 15:42
字数 868
阅读 30
收藏 0

使用NSTimer出现的问题


去年封的一个图片轮播的, 这两天在忙着给重新封装一下, 增加更多的方法, 有更多个性化的设置, 增加了网络请求图片的轮播. 重新封装, 这个过程还算顺利, 但是到计时器那块卡住了.

WHImagePlayer图片轮播和图片浏览器: https://github.com/hell03W/WHImagePlayer, 欢迎star支持一下, 如果有任何问题欢迎issue给我.

问题是这样的:

简单来说, 其实就是计时器, 我用的NSTimer, 是在一个自定义view中创建NSTimer的, 如果是在控制器中, 可以在viewWillDisappear:中执行NSTimer的invalidate方法, timer对象是可以被正常销毁的, 但是在自定义的view里面没有那样的方法! 有人会说可以将target设置成__weak类型的就可以了嘛 ! 我也是那样认为的, 可是试验证明, 那样是不行的(要是那么简单, 也没必要写个blog来记录了).

经过在网上查找资料, 和自己的思考, 最终总结了几种可行方案:

方案一:

如下代码所示, 使用dispatch_after可以完美解决, 但是需要注意的是, 在block内部, 使用self时候必须使用weakSelf, 如果直接使用self, 还是不会被释放掉的.

    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [UIView animateWithDuration:0.3 animations:^{
            weakSelf.imageScrollView.contentOffset = CGPointMake(weakSelf.width*2, 0);
        } completion:^(BOOL finished) {
            if (finished) {
                [weakSelf scrollViewDidEndDecelerating:weakSelf.imageScrollView];
                [weakSelf setupTimer];
            }
        }];
    });

方案2:

使用一个假冒的对象作为target. 原理也不复杂, 创建一个类, 让新的类拥有self的弱引用, 通过这个类的方法, 将需要作为target的"self"和要执行的方法的名字"selector", 传入新的类内部, 在新的类内部, 调用"self""selector"方法, 在自定义view的NSTimer方法中调用新的类的调用外部类方法的方法.

上代码:

WHTimerTarget.h

 #import <Foundation/Foundation.h>

@interface WHTimerTarget : NSObject

/**1. 调用这个方法  传入target和selector和时间, 就会间隔timeInterval秒执行target的selector方法.
    内部使用NSTimer实现, 主要是为了解决, NSTimer会出现循环引用的问题
 */
+ (void)addTarget:(id)target selector:(SEL)selector timeInterval:(NSTimeInterval)timeInterval;

/// 2. 如果如要NSTimer写在本类外面, 可以使用这个方法
+ (instancetype)timerTarget:(id)target selector:(SEL)selector;

- (void)timerDidFire:(NSTimer *)timer;

@end

WHTimerTarget.m

 #import "WHTimerTarget.h"

@implementation WHTimerTarget
{
    __weak id  _target;
    SEL _selector;
}

- (instancetype)initWithTarget:(id)target selector:(SEL)selector {
    self = [self init];
    _target = target;
    _selector = selector;
    return self;
}

+ (instancetype)timerTarget:(id)target selector:(SEL)selector {
    return [[self alloc] initWithTarget:target selector:selector];
}

- (void)timerDidFire:(NSTimer *)timer
{
    if(_target)
    {
        [_target performSelector:_selector withObject:timer];
    }
    else
    {
        [timer invalidate];
    }
}

+ (void)addTarget:(id)target selector:(SEL)selector timeInterval:(NSTimeInterval)timeInterval
{
    id timerTarget = [[self alloc] initWithTarget:target selector:selector];
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:timeInterval
                                                      target:timerTarget
                                                    selector:@selector(timerDidFire:)
                                                    userInfo:nil
                                                     repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

@end

如上代码所示, 就是新的类, 伪target的全部代码. 使用的方法有两种, 如下:

 1, 使用方法:
 id target = [TimerTarget timerTarget:<#self#> selector:@selector(<#automaticScroll:#>)];
 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:<#self.autoScrollTimeInterval#> target:target selector:@selector(timerDidFire:) userInfo:nil repeats:YES];
 
 2, 使用方法:
 [TimerTarget addTarget:<#self#> selector:@selector(<#automaticScroll:#>) timeInterval:<#3#>];

写在后面的:

目前为止, 我只发现这两种比较好用的方法, 如果谁有更好的方案, 欢迎留言交流 .

© 著作权归作者所有

hell03W
粉丝 9
博文 145
码字总数 109892
作品 0
朝阳
程序员
私信 提问
ios-常见的循环引用

介绍: 循环引用,指的是多个对象相互引用时,使得引用形成一个环形,导致外部无法真正是否掉这块环形内存。其实有点类似死锁。 举个例子:A->B->C->....->X->B ->表示强引用,这样的B的引用...

余成海
2016/04/12
1K
0
iOS 面试题~避免循环引用~解决方法

//联系人:石虎QQ:1224614774昵称:嗡嘛呢叭咪哄 一、概念: 循环引用:指的是多个对象相互引用时,使得引用形成一个环形,导致外部无法真正是否掉这块环形内存。其实有点类似死锁。 其实循环引用...

石虎132
2017/12/22
0
0
iOS查看屏幕帧数工具--YYFPSLabel

学习 YYKit 代码时,发现 ibireme 在项目里加入的一个查看当前屏幕帧数的小工具,效果如下: 挺实用,实现方法也很简单,但是思路特别棒。 这里是Demo: YYFPSLabel 这里我把这个小工具从 中...

yehot
2016/04/05
0
0
iOS中控制器的释放问题

ARC工程是可以重写dealloc方法并被系统调用的,但不需要手动调用父类的dealloc,手写[super dealloc]方法会报错,事实上系统会自动帮你调用父类的dealloc方法,不需要你实现。可以通过在dea...

no_wait
2016/01/23
149
0
NSDate的计算问题、日期计算、时区问题、NSTimer

一.NSDate的计算问题 NSTimeInterval 是一个以秒为单位的时间片。 1.可以用initWithTimeIntervalSinceNow方法传入一个NSTimeInterval对象,创建一个NSDate对象。 NSDate tomorrow =[[NSDat...

唐丽梅
2013/04/25
10.4K
0

没有更多内容

加载失败,请刷新页面

加载更多

PostgreSQL参数search_path影响及作用

search_path稍微熟悉PG就会用到,用法这里就不必讲,本篇主要讲它在程序里怎样处理。 1、GUC参数定义 这是个 config_string 参数 {{"search_path", PGC_USERSET, CLIENT_CONN_STATEMENT,...

有理想的猪
今天
9
0
Qt程序各个平台打包发布及安装程序大全

本文链接:https://blog.csdn.net/zhengtianzuo06/article/details/78468111 通用: 1.准备图标 图标可以直接使用一般格式的图片制作, 比如jpg, png等 推荐使用Photoshop制作原始图 推荐使用I...

shzwork
今天
12
0
springboot2.0 maven打包分离lib,resources

springboot将工程打包成jar包后,会出现获取classpath下的文件出现测试环境正常而生产环境文件找不到的问题,这是因为 1、在调试过程中,文件是真实存在于磁盘的某个目录。此时通过获取文件路...

陈俊凯
今天
23
0
BootStrap

一、BootStrap 简洁、直观、强悍的前端开发框架,让web开发更加迅速、简单 中文镜像网站:http://www.bootcss.com 用于开发响应式布局、移动设备优先的WEB项目 1、使用boot 创建文件夹,在文...

wytao1995
今天
10
0
小知识:讲述Linux命令别名与资源文件的区别

别名 别名是命令的快捷方式。为那些需要经常执行,但需要很长时间输入的长命令创建快捷方式很有用。语法是: alias ppp='ping www.baidu.com' 它们并不总是用来缩短长命令。重要的是,你将它...

老孟的Linux私房菜
今天
26
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部