NSRunLoop - 运行循环 - 是一个死循环
UIApplicationMain返回值为int类型,UIApplicationMain内部开启一个主线程,保证Runloop所在线程不退出。
目的:
-- 保证程序不退出。 本质,保证Runloop所在线程不退出。
-- 负责监听事件。 (触摸,时钟,网络)
每条线程都有一个RunLoop,但是默认都不开启(run)。子线程需要手动开启,主线程由系统 自动开启。
//@property (nonatomic, strong) NSThread * thread; 只保存了对象,没有保持线程。
//Runloop 5种模式
/**
NSRunLoopCommonModes - 占位模式(UI && 默认)
NSDefaultRunLoopMode - 默认模式 处理非NSConnection对象的事件。
UITrackingRunLoopMode - UI模式 只有发生UI事件时才会生效。 专门处理UI事件。
GSEventReceiveRunLoopMode - 用于接受系统事件,属于内部的Run Loop模式。
UIInitializationRunLoopMode - 在刚启动App时进入的第一个Mode,启动完成后不再使用
//以下是官方文档中的五种模式,跟其他资料看到的不太一样,有清楚的请指教。
NSRunLoopCommonModes
Objects added to a run loop using this value as the mode are monitored by all run loop modes that have been declared as a member of the set of “common" modes; see the description of CFRunLoopAddCommonMode for details.
NSDefaultRunLoopMode
The mode to deal with input sources other than NSConnection objects.
NSEventTrackingRunLoopMode
A run loop should be set to this mode when tracking events modally, such as a mouse-dragging loop.
NSModalPanelRunLoopMode
A run loop should be set to this mode when waiting for input from a modal panel, such as NSSavePanel or NSOpenPanel.
UITrackingRunLoopMode
The mode set while tracking in controls takes place. You can use this mode to add timers that fire during tracking.
*/
Source0:只包含了一个回调(函数指针),并不能主动发出事件,需要先调用CFRunLoopSourceSignal(source)
将这个source标记为待处理,然后主动调用CFRunLoopWeakUp(runloop)
来唤醒runloop
非系统内核事件的处理。
Source1:包含了一个mach-port
和一个回调(函数指针),被用于通过内核和其他线程相互发送消息,这种Source能主动唤醒runloop
。
//创建定时器
dispatch_source_t 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.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//设置回调
dispatch_source_set_event_handler(timer, ^{
NSLog(@"------%@",[NSThread currentThread]);
});
//启动
dispatch_resume(timer);
Timer
NSThread * thread = [[NSThread alloc] initWithBlock:^{
NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];//开启循环,循环执行完成之前,下面代码不执行。
NSLog(@"%@",[NSThread currentThread]);
}];
[thread start];
Observer
typedef void(^RunloopBlock)(void);
//任务数组 存放任务。
@property (nonatomic, strong) NSMutableArray<RunloopBlock> * taskes;
//添加Runloop的观察者
- (void)addRunloopObserver{
//获取runloop
CFRunLoopRef runloop = CFRunLoopGetCurrent();
//定义观察者
static CFRunLoopObserverRef defaultModeObserver;
//创建上下文
CFRunLoopObserverContext context = {
0,
(__bridge void *)(self),//传入self,方便之后操作。如果不需要,&context直接传nil。
&CFRetain,
&CFRelease,
NULL,
};
//创建观察者 ,
defaultModeObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, YES, 0, &callBack, &context);
/**
kCFRunLoopBeforeWaiting观察NSRunLoop等待之前,如果需要一直观察,可以添加下列代码,不过要注意CPU使用率。。。。并不好用。。。。
[NSTimer scheduledTimerWithTimeInterval:0.001 repeats:YES block:^(NSTimer * _Nonnull timer) {
//什么都不做,只为保持RunLoop活动。
}];
*/
//添加观察者到当前runLoop中
CFRunLoopAddObserver(runloop, defaultModeObserver, kCFRunLoopDefaultMode);
}
//回调
static void callBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
NSLog(@"%@",[NSThread currentThread]);
//取出任务 执行
ViewController * vc = (__bridge ViewController*)info;
if (vc.taskes.count == 0) {
return;
}
RunloopBlock task = vc.taskes.firstObject;
task();
[vc.taskes removeObjectAtIndex:0];
}
//NSTimer 两个创建方法的区别。
/// Creates and returns a new NSTimer object initialized with the specified block object. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire.
//创建并返回新初始化的NSTimer对象,需要手动添加到NSRunLoop中,才能启动。
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
/// Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the current run loop in the default mode.
//创建并返回新初始化的NSTimer对象,并自动在当前NSRunLoop的默认模式下进行调用。
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
@autoreleasepool
App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。
第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。
第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。autoreleasepool引用:
作者:thinkq
链接:https://www.jianshu.com/p/a2999d7728b4
来源:简书
网友评论