基于Runloop的任务管理器

2020-06-12  本文已影响0人  格雷s

1、工具背景

2、实现机制

- (void)addRunloopObserver {
    CFRunLoopObserverContext context = {
        0,
        ( __bridge void *)(self),
        &CFRetain,
        &CFRelease,
        NULL
    };
    //监听runloop即将进入睡眠状态
    static CFRunLoopObserverRef defaultModeObsever;
    defaultModeObsever = CFRunLoopObserverCreate(NULL,
                                                 kCFRunLoopBeforeWaiting,
                                                 YES,
                                                 NSIntegerMax,
                                                 &Callback,
                                                 &context
                                                 );
    
    //添加RunLoop的观察者
    CFRunLoopAddObserver(CFRunLoopGetMain(), defaultModeObsever, kCFRunLoopCommonModes);
    CFRelease(defaultModeObsever);
}

3、实现步骤

+ (void)addTask:(void(^)(void))task {
    [self addTarget:nil task:task];
}

+ (void)addTarget:(id)target task:(void(^)(void))task {
    [self addTarget:target uniqueKey:nil task:task];
}
//添加任务
+ (void)addTarget:(id)target uniqueKey:(NSString *)uniqueKey task:(void(^)(void))task {
    if (![NSThread isMainThread]) {
        //在子线程中添加的任务,最终执行的时候不是在原来的子线程,为了避免不必要的线程处理问题,请在mainThread中添加task
        return;
    }
    GLRunloopTaskTool *taskTool = [GLRunloopTaskTool shareInstance];
    //如果target存在task,查看是否需要检查uniqueKey
    id tar = target ? : taskTool;
    NSMutableDictionary *taskInfo = [taskTool.taskCache objectForKey:tar];
    if (!taskInfo) {
        taskInfo = [NSMutableDictionary dictionary];
        [taskTool.taskCache setObject:taskInfo forKey:tar];
    }
    if (uniqueKey) {
        [taskInfo setObject:task forKey:uniqueKey];
    } else {
        NSString *key = [NSString stringWithFormat:@"gl_runloop_task_tool_value_%d",taskTool.increase_Index % INT_MAX];
        [taskInfo setObject:task forKey:key];
    }
    taskTool.increase_Index++;
}

+ (void)removeTasks:(id)target {
    GLRunloopTaskTool *taskTool = [GLRunloopTaskTool shareInstance];
    id tar = target ? : taskTool;
    [taskTool.taskCache removeObjectForKey:tar];
}

+ (void)removeAllTasks {
    [[GLRunloopTaskTool shareInstance].taskCache removeAllObjects];
}

4、Observer回调/Task执行

static void Callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
    GLRunloopTaskTool *taskTool = (__bridge GLRunloopTaskTool *)(info);
    if (taskTool.taskCache.count) {
        NSLog(@"start task");
        id target = taskTool.taskCache.keyEnumerator.allObjects.firstObject;
        NSLog(@"target = %@",target);
        NSMutableDictionary *taskInfo = [taskTool.taskCache objectForKey:target];
        NSLog(@"taskInfo start = %@",taskInfo);
        NSString *taskKey = taskInfo.allKeys.firstObject;
        void(^task)(void) = [taskInfo objectForKey:taskKey];
        if (task) {
            //执行任务
            task();
            NSLog(@"excute task=%@",task);
        }
        [taskInfo removeObjectForKey:taskKey];
        NSLog(@"taskInfo end = %@",taskInfo);
        if (taskInfo.count == 0) {
            [taskTool.taskCache removeObjectForKey:target];
            NSLog(@"taskInfo.count== %lu,taskCache.count=%lu",(unsigned long)taskInfo.count,(unsigned long)taskTool.taskCache.count);
        }
        if (taskTool.taskCache.count) {
            CFRunLoopWakeUp(CFRunLoopGetMain());
        }
    }
}
改进的地方、有疑问的地方尽情留言

Demo地址

上一篇下一篇

猜你喜欢

热点阅读