• 可控制生命周期的常驻线程


    - (void)testWorkThread {
        self.thread = [AlwaysLiveThread new];
        [self.thread startThisThread];
        int count = 0;
        int __block writeItem = 0;
        int __block checkCount = 0;
        while (count < 10) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(count * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self.thread workJob:^{
                    NSLog(@"正在执行任务(%d)",count);
                    ++writeItem;
                }];
            });
            count++;
        }
        [self.thread waitConditions:^BOOL(BOOL *stop) {
            *stop = (writeItem == 3);
            if (*stop) {
                NSLog(@"输出第3个数字了");
            }
            NSLog(@"当前已进行%d次条件检索",++checkCount);
            return *stop;
        } onThread:[NSThread mainThread] timegap:0.2 timeout:4.0 then:^(BOOL success) {
            NSLog(@"条件等待:%@",success?@"成功":@"失败");
        }];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self.thread stopThisThread];
            self.thread = nil;
        });
    }
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    typedef BOOL (^ThreadWaitConditionsBlock)(BOOL*);
    typedef void (^ThreadConditionsCheckFinshBlock)(BOOL);
    typedef void (^ThreadWillInsertJobBlock)(void);
    
    @interface AlwaysLiveThread : NSObject
    /**
     @param block 加入到线程中进行处理的block
     */
    - (void)workJob:(ThreadWillInsertJobBlock)block;
    /**
    @param block 加入到线程中进行处理的block
     @param afterDelay 延迟执行的时间(与上一个方法实现的原理不一致)
    */
    - (void)workJob:(ThreadWillInsertJobBlock)block afterDelay:(NSTimeInterval)afterDelay;
    /**
     启动这个线程,线程不启动所有方法都不会执行
     */
    - (BOOL)startThisThread;
    /**
     结束这个线程,线程一结束所有的方法都不会继续执行了
     */
    - (BOOL)stopThisThread;
    
    /**
     开启一个条件判断,条件符合或者等待超时执行then方法
     @param conditions 判断条件
     @param thread 回调的线程
     @param timegap 检测的间隔(非精准触发)
     @param timeout 最大等待时间
     @param then 等待完成后执行的方法
     */
    - (void)waitConditions:(ThreadWaitConditionsBlock)conditions onThread:(NSThread*)thread timegap:(NSTimeInterval)timegap timeout:(NSTimeInterval)timeout then:(ThreadConditionsCheckFinshBlock)then;
    
    @end
    
    NS_ASSUME_NONNULL_END
    #import "AlwaysLiveThread.h"
    
    @interface AlwaysLiveThread()
    {
        CFRunLoopSourceContext context;
        CFRunLoopRef runLoop;
        CFRunLoopSourceRef runLoopSource;
    }
    
    @property (nonatomic, strong) NSThread *workThread;
    @property (nonatomic, assign) BOOL isStarted;
    @property (nonatomic, assign) BOOL isStoped;
    
    @end
    
    static const NSString *kAfterDelayDurationKey = @"kAfterDelayDurationKey";
    static const NSString *kFireTimestampKey = @"kFireTimestampKey";
    static const NSString *kJobBlockKey = @"kJobBlockDurationKey";
    static const NSString *kRunningThreadKey = @"kRunningThreadKey";
    static const NSString *kBlockParamKey = @"kBlockParamKey";
    
    @implementation AlwaysLiveThread
    
    - (instancetype)init {
        return [self initWithBlock:^{
            
        }];
    }
    
    - (instancetype)initWithBlock:(ThreadWillInsertJobBlock)block {
        self = [super init];
        if (self) {
            self.isStarted = NO;
            self.isStoped = NO;
            self.workThread = [[NSThread alloc] initWithTarget:self selector:@selector(startThreadByBlock:) object:block];
        }
        return self;
    }
    
    - (BOOL)startThisThread {
        BOOL isStarted = self.isStarted;
        if (!self.isStarted && !self.isStoped) {
            [self.workThread start];
        }
        return (!self.isStoped && !isStarted);
    }
    
    - (void)startThreadByBlock:(ThreadWillInsertJobBlock)block {
        if (!self.isStarted && !self.isStoped) {
            !block?:block();
            [self registerRunloopSourceThenRunning];
        }
    }
    
    - (void)registerRunloopSourceThenRunning {
        if (!self.isStarted && !self.isStoped) {
            self.isStarted = YES;
            runLoop = CFRunLoopGetCurrent();
            runLoopSource = CFRunLoopSourceCreate(NULL, 0, &context);
            CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
            CFRunLoopRun();
        }
    }
    
    - (void)stopThisRunloopWhileDisableThread {
        if (!self.isStoped && self.isStarted) {
            CFRunLoopStop(runLoop);
            CFRunLoopRemoveSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
            CFRelease(runLoopSource);
            CFRelease(&context);
            self.isStoped = YES;
        }
    }
    
    - (void)waitConditions:(ThreadWaitConditionsBlock)conditions onThread:(NSThread*)thread timegap:(NSTimeInterval)timegap timeout:(NSTimeInterval)timeout then:(ThreadConditionsCheckFinshBlock)then {
        BOOL __block shouldStop = NO;
        NSTimeInterval timestamp = CFAbsoluteTimeGetCurrent();
        typeof(self) __weak weakself = self;
        ThreadWillInsertJobBlock __block blockItem = nil;
        ThreadWillInsertJobBlock block = ^{
            typeof(weakself) __strong strongself = weakself;
            NSTimeInterval fireTimestamp = CFAbsoluteTimeGetCurrent();
            NSTimeInterval didTimeout = fireTimestamp - timestamp;
            BOOL flag = conditions(&shouldStop);
            if (shouldStop || didTimeout >= timeout) {
                if (then) {
                    [strongself callbackJobInOtherThread:@{
                        kJobBlockKey : then,
                        kBlockParamKey : @(flag),
                        kRunningThreadKey : thread ? : [NSThread currentThread],
                    }];
                }
            } else {
                [strongself workJob:blockItem afterDelay:MIN(timegap, (timeout - didTimeout))];
            }
        };
        blockItem = block;
        block();
    }
    
    - (void)callbackJobInOtherThread:(NSDictionary*)userInfo {
        ThreadConditionsCheckFinshBlock then = userInfo[kJobBlockKey];
        id param = userInfo[kBlockParamKey];
        BOOL flag = [(NSNumber*)param boolValue];
        NSThread *thread = userInfo[kRunningThreadKey] ? : [NSThread currentThread];
        ThreadWillInsertJobBlock block = ^{
            !then?:then(flag);
        };
        [self performSelector:@selector(doCallbackJobInOtherThread:) onThread:thread withObject:block waitUntilDone:NO];
    }
    
    - (void)doCallbackJobInOtherThread:(ThreadWillInsertJobBlock)block {
        !block?:block();
    }
    
    - (void)workJob:(ThreadWillInsertJobBlock)block {
        if (block) {
            [self performSelector:@selector(doNewJob:) onThread:self.workThread withObject:block waitUntilDone:NO];
        }
    }
    
    - (void)doNewJob:(ThreadWillInsertJobBlock)block {
        !block?:block();
    }
    
    - (void)workJob:(ThreadWillInsertJobBlock)block afterDelay:(NSTimeInterval)afterDelay {
        if (block) {
            if (afterDelay <= 0.0) {
                [self workJob:block];
            } else {
                NSTimeInterval timestamp = CFAbsoluteTimeGetCurrent();
                NSTimeInterval fireTimestamp = timestamp + afterDelay;
                [self performSelector:@selector(doNewJobAfterDelay:) onThread:self.workThread withObject:@{kJobBlockKey : block,
                                                                                                           kFireTimestampKey : @(fireTimestamp),
                } waitUntilDone:NO];
            }
        }
    }
    
    - (void)doNewJobAfterDelay:(NSDictionary*)userInfo {
        NSTimeInterval fireTimestamp = [userInfo[kFireTimestampKey] doubleValue];
        void (^block)(void) = userInfo[kJobBlockKey];
        NSTimeInterval timestamp = CFAbsoluteTimeGetCurrent();
        NSTimeInterval afterDelay = fireTimestamp - timestamp;
        if (afterDelay <= 0.0) {
            [self doNewJob:block];
        } else {
            [self performSelector:@selector(doNewJob:) withObject:block afterDelay:afterDelay];
        }
    }
    
    - (BOOL)stopThisThread {
        BOOL isStoped = self.isStoped;
        if (self.isStarted && !self.isStoped) {
            [self.class cancelPreviousPerformRequestsWithTarget:self];
            /// 放在线程内执行,主要是避免跨线程操作异常(比如调用启动后立即停止,导致数据访问异常)
            [self performSelector:@selector(stopThisRunloopWhileDisableThread) onThread:self.workThread withObject:nil waitUntilDone:NO];
        }
        return (self.isStarted && !isStoped);
    }
    
    - (void)dealloc {
    #ifdef DEBUG
        NSLog(@"任务线程%@被销毁",self);
    #endif
    }
    
    @end
  • 相关阅读:
    TCP/IP讲解
    Android开发的技术层次
    页面右下角弹出类似QQ或MSN的消息提示
    C# winform 自定义鼠标图标
    C#遍历指定文件夹中的所有文件
    C#操作Word
    关于数据绑定的一些小技巧
    Silverlight遍历本地文件夹
    ckeditor+ckfinder+syntaxhighlight实现上传和插入代码高亮(for .NET)
    wpf 动画效果
  • 原文地址:https://www.cnblogs.com/yuxiaoyiyou/p/13162748.html
Copyright © 2020-2023  润新知