iOS 全局定时器

2018-05-02  本文已影响167人  moxacist

我们在项目开发过程中有时会遇到这种需求:

我的做法是开启个全局定时器,有对象要计时的时候调用addNotificationObserver:(id)observer type:(MDGlobalTimerType)type selector:(SEL)seletor把注册到MDGlobalTimer类里,

在对象delloc或者释放的时候调用removeNotificationObserver:(id)observer type:(MDGlobalTimerType)type方法注销对象

然后在add的方法中开启一个定时器(已开启就不开了)
在remove方法中判断数组里还有对象没,没有的话表明没有需要计时的对象,就停止定时器并销毁
计时:每过一定时间(这里设置成1s),发出通知(add方法里已经注册了通知),然后执行对象的方法,进行刷新UI

- (void)addNotificationObserver:(id)observer type:(MDGlobalTimerType)type selector:(SEL)seletor{
   
    BOOL addNotification = NO;
    NSString *notificationName = nil;
    switch (type) {
        case MDGlobalTimerTypeOneSecond:
        {
            NSMutableSet *secondsObservers = [NSMutableSet setWithSet:_observers[kOneSecond]];
            if (![secondsObservers containsObject:observer]) {
               [secondsObservers addObject:observer];
                addNotification = YES;
                notificationName = notification_kOneSecond;
                _observers[kOneSecond] = secondsObservers;
            }
            
        }
            break;
        case MDGlobalTimerTypeHalfMinute:
        {
            NSMutableSet *halfMinuteObservers = [NSMutableSet setWithSet:_observers[kHalfMinute]];
            if (![halfMinuteObservers containsObject:observer]) {
                [halfMinuteObservers addObject:observer];
                addNotification = YES;
                notificationName = notification_kHalfMinute;
                _observers[kHalfMinute] = halfMinuteObservers;
            }
            
        }
            break;
        case MDGlobalTimerTypeOneMinute:
        {
            NSMutableSet *oneMinuteObservers = [NSMutableSet setWithSet:_observers[kOneMinute]];
            if (![oneMinuteObservers containsObject:observer]) {
                [oneMinuteObservers addObject:observer];
                addNotification = YES;
                notificationName = notification_kOneMinute;
                _observers[kOneMinute] = oneMinuteObservers;
            }   
        }
            break;
        default:
            break;
    }
    
    //添加通知
    if (addNotification) {
        [[NSNotificationCenter defaultCenter] addObserver:observer selector:seletor name:notificationName object:nil];
    }
    
    //开启定时器
    [self startTiming];
    
}
- (void)removeNotificationObserver:(id)observer type:(MDGlobalTimerType)type{
    
    NSString *notificationName = nil;
    switch (type) {
        case MDGlobalTimerTypeOneSecond:
        {
            NSMutableSet *secondsObservers = _observers[kOneSecond];
            [secondsObservers removeObject:observer];
            _observers[kOneSecond] = secondsObservers;
            notificationName = notification_kOneSecond;
        }
            break;
        case MDGlobalTimerTypeHalfMinute:
        {
            NSMutableSet *halfMinuteObservers = _observers[kHalfMinute];
            [halfMinuteObservers removeObject:observer];
            _observers[kHalfMinute] = halfMinuteObservers;
            notificationName = notification_kHalfMinute;
        }
            break;
        case MDGlobalTimerTypeOneMinute:
        {
            NSMutableSet *oneMinuteObservers = _observers[kOneSecond];
            [oneMinuteObservers removeObject:observer];
            _observers[kOneSecond] = oneMinuteObservers;
            notificationName = notification_kOneMinute;
        }
            break;
        default:
            break;
    }
    
    //移除监听
    [[NSNotificationCenter defaultCenter] removeObserver:observer name:notificationName object:nil];
    //移除空set
    [_observers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSMutableSet * _Nonnull obj, BOOL * _Nonnull stop) {
        if (obj.count == 0) {
            [_observers removeObjectForKey:key];
        }
    }];
    
    //关闭定时器
    [self stopTiming];
}

启动定时器:

static NSString *const kOneSecond = @"kOneSecond";
static NSString *const kHalfMinute = @"kHalfMinute";
static NSString *const kOneMinute = @"kOneMinute";

@implementation MDGlobalTimer{
    dispatch_source_t _timer;
    int _seconds;
    NSMutableDictionary <NSString *,NSMutableSet*> *_observers;
}

+ (id)allocWithZone:(struct _NSZone *)zone{
    return [self sharedInstance];
}

+ (instancetype)sharedInstance{
    static MDGlobalTimer *timer;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        timer = [[super allocWithZone:nil] init];
        timer->_observers = @{}.mutableCopy;
        
    });
    return timer;
}


/** 开启定时器 */
- (void)startTiming{
    if (_timer) {
        return;
    }
    _seconds = 0;
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(_timer, ^{
        _seconds++;
        dispatch_sync(dispatch_get_main_queue(), ^{
            //发送s
            if (_observers[kOneSecond].count > 0) {
                [[NSNotificationCenter defaultCenter] postNotificationName:notification_kOneSecond object:nil];
            }
            //发送半分钟通知
            if (_seconds%30 == 0 && _observers[kHalfMinute].count > 0) {
                [[NSNotificationCenter defaultCenter] postNotificationName:notification_kHalfMinute object:nil];
            }
            
            //发送1分钟通知
            if (_seconds%60 == 0 && _observers[kOneMinute].count > 0) {
                [[NSNotificationCenter defaultCenter] postNotificationName:notification_kOneMinute object:nil];
                _seconds = 0;
            }
        });
    });
    dispatch_resume(_timer);
}

/** 结束定时器 */
- (void)stopTiming{
    if (_timer && _observers.count == 0) {
        dispatch_source_cancel(_timer);
        _timer = nil;
    }
}

这里由于工程中只有分、秒、30s的定时需求,所以只写死了这三个,如果有更细节的定时,可以在add方法里加计时间隔,并在计时时以最大公因数判断

如果有什么不对的地方,希望评论指正下œ∑®
MDGlobalTimer-demo

上一篇 下一篇

猜你喜欢

热点阅读