美文网首页
iOS 全局定时器

iOS 全局定时器

作者: moxacist | 来源:发表于2018-05-02 14:51 被阅读167次

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

    • tableview等列表中会含有多个倒计时的UI
    • 在启动某个操作就需要定时器重复执行某个动作(比如上传地理坐标,心跳)

    我的做法是开启个全局定时器,有对象要计时的时候调用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

    相关文章

      网友评论

          本文标题:iOS 全局定时器

          本文链接:https://www.haomeiwen.com/subject/ngfzkftx.html