使用NSTimer出现的问题

使用NSTimer出现的问题


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

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

问题是这样的:浏览器

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

通过在网上查找资料, 和本身的思考, 最终总结了几种可行方案:app

方案一:oop

以下代码所示, 使用dispatch_after能够完美解决, 可是须要注意的是, 在block内部, 使用self时候必须使用weakSelf, 若是直接使用self, 仍是不会被释放掉的.spa

__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:code

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

上代码:对象

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#>];

写在后面的:

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

相关文章
相关标签/搜索