RunLoop知识点
NSRunLoop
是 CFRunLoopRef
的包装类
NSRunLoop
是OC
对象
CFRunLoopRef
是core Foundation
库中的定义
NSRunLoop的状态
// App运行的默认状态
NSDefaultRunLoopMode
// NSRunLoopCommonModes不是一种实际状态
// 而是NSDefaultRunLoopMode 和 UITrackingRunLoopMode 的集合
NSRunLoopCommonModes
CFRunLoop的状态
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即将进入loop
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理timer
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理source
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
kCFRunLoopExit = (1UL << 7), // 即将退出loop
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
RunLoop
状态监听
//1.创建监听者
/*
第一个参数:怎么分配存储空间
第二个参数:要监听的状态 kCFRunLoopAllActivities 所有的状态
第三个参数:时候持续监听
第四个参数:优先级 总是传0
第五个参数:当状态改变时候的回调
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
/*
kCFRunLoopEntry = (1UL << 0), 即将进入runloop
kCFRunLoopBeforeTimers = (1UL << 1), 即将处理timer事件
kCFRunLoopBeforeSources = (1UL << 2),即将处理source事件
kCFRunLoopBeforeWaiting = (1UL << 5),即将进入睡眠
kCFRunLoopAfterWaiting = (1UL << 6), 被唤醒
kCFRunLoopExit = (1UL << 7), runloop退出
kCFRunLoopAllActivities = 0x0FFFFFFFU
*/
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"即将进入runloop");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"即将处理timer事件");
break;
case kCFRunLoopBeforeSources:
NSLog(@"即将处理source事件");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"即将进入睡眠");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"被唤醒");
break;
case kCFRunLoopExit:
NSLog(@"runloop退出");
break;
default:
break;
}
});
/*
第一个参数:要监听哪个runloop
第二个参数:观察者
第三个参数:运行模式
NSDefaultRunLoopMode == kCFRunLoopDefaultMode
NSRunLoopCommonModes == kCFRunLoopCommonModes
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(),observer, kCFRunLoopDefaultMode);
// 销毁observer
CFRelease(observer);
OC版代码实现
//=======================.h===========================
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PSKeepAliveThread : NSObject
/// 执行任务
/// @param task 任务block
- (void)executeTask:(void (^)(void))task;
/// 停止线程
- (void)stopThread;
@end
NS_ASSUME_NONNULL_END
//=======================.m===========================
#import "PSKeepAliveThread.h"
@interface PSKeepAliveThread ()
@property (nonatomic, strong) NSThread *innerThread;
@property (nonatomic, assign) BOOL isStop;
@property (nonatomic, assign) BOOL isRun;
@end
@implementation PSKeepAliveThread
- (instancetype)init {
if (self = [super init]) {
__weak typeof(self) weakSelf = self;
self.innerThread = [[NSThread alloc] initWithBlock:^{
// thread start
//获取当前线程的runloop,并且给线程添加一个NSPort(source)
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
// 使用弱引用,保证isStop变量在设置为YES时,能退出循环
while (weakSelf && !weakSelf.isStop) {
// 当程序运行到这里时,如果没有需要执行的任务,则线程会进入休眠状态,并且不会继续执行while循环
// 直到有任务要执行时,才会被唤醒
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
// thread end
}];
// 启动线程
[self run];
}
return self;
}
- (void)run {
if (!self.isRun) {
self.isRun = YES;
[self.innerThread start];
}
}
- (void)executeTask:(void (^)(void))task {
// 如果线程已经结束了,或者任务为空的情况,不执行任务
if (!self.innerThread || !task) return;
//将任务放到线程中执行
[self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:task waitUntilDone:NO];
}
- (void)__executeTask:(void (^)(void))task {
task();
}
// 停止线程
- (void)stopThread {
if (!self.innerThread) return;
[self performSelector:@selector(__stopThread) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}
- (void)__stopThread {
self.isStop = YES;
self.isRun = NO;
// 停止当前线程的Runloop
CFRunLoopStop(CFRunLoopGetCurrent());
self.innerThread = nil;
}
- (void)dealloc {
//当前类释放时,停止线程
[self stopThread];
}
@end
C语言版实现
#import "PSKeepAliveThread.h"
@interface PSKeepAliveThread ()
@property (nonatomic, strong) NSThread *innerThread;
@property (nonatomic, assign) BOOL isRun;
@end
@implementation PSKeepAliveThread
- (instancetype)init {
if (self = [super init]) {
self.innerThread = [[NSThread alloc] initWithBlock:^{
// thread start
// 创建上下文
CFRunLoopSourceContext context = {0};
// 创建source
CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
// 向Runloop中添加source
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
// 销毁source
CFRelease(source);
// 运行runloop
// 第三个参数returnAfterSourceHandled: 设置为true时,代表执行完任务之后就会退出当前loop
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, false);
// thread end
}];
// 启动线程
[self run];
}
return self;
}
- (void)run {
if (!self.isRun) {
self.isRun = YES;
[self.innerThread start];
}
}
- (void)executeTask:(void (^)(void))task {
// 如果线程已经结束了,或者任务为空的情况,不执行任务
if (!self.innerThread || !task) return;
//将任务放到线程中执行
[self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:task waitUntilDone:NO];
}
- (void)__executeTask:(void (^)(void))task {
task();
}
// 停止线程
- (void)stopThread {
if (!self.innerThread) return;
[self performSelector:@selector(__stopThread) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}
- (void)__stopThread {
self.isRun = NO;
// 停止当前线程的Runloop
CFRunLoopStop(CFRunLoopGetCurrent());
self.innerThread = nil;
}
- (void)dealloc {
//当前类释放时,停止线程
[self stopThread];
}
@end
使用
#import "ViewController.h"
#import "PSKeepAliveThread.h"
@interface ViewController ()
@property (nonatomic, strong) PSKeepAliveThread *thread;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.thread = [[PSKeepAliveThread alloc] init];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.thread executeTask:^{
NSLog(@"执行任务 %@", [NSThread currentThread]);
}];
}
// 点击按钮,停止线程
- (IBAction)stopThreadAction:(UIButton *)sender {
[self.thread stopThread];
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self.thread stopThread];
}
@end