本文属笔记性质,主要针对本身理解不太透彻的地方进行记录。ios
推荐系统直接学习小码哥iOS底层原理班---MJ老师的课确实不错,强推一波。数组
iOS系统在程序运行过程当中循环作一些事情bash
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
return 0; 则程序会直接退出。
}
}
复制代码
[NSRunLoop currentRunLoop]; // 得到当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 得到主线程的RunLoop对象
复制代码
CFRunLoopModeRef表明RunLoop的运行模式网络
一个RunLoop包含若干个Mode,每一个Mode又包含若干个Source0/Source1/Timer/Observerasync
RunLoop启动时只能选择其中一个Mode,做为currentMode函数
若是须要切换Mode,只能退出当前Loop,再从新选择一个Mode进入oop
不一样组的Source0/Source1/Timer/Observer能分隔开来,互不影响性能
App的默认Mode,一般主线程是在这个Mode下运行学习
界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其余 Mode 影响ui
会进行
_commonModes
标记,只要_modes
符合_commonModes
都会执行。
_commonModeItems
表明着能在Common模式下工做的单元,好比timer。
Source0
去处理底层也是
NSTimer
runloop休眠以前刷新
清理内部须要释放的对象
void observeRunLoopActicities(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"kCFRunLoopEntry");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"kCFRunLoopBeforeTimers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"kCFRunLoopBeforeSources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"kCFRunLoopBeforeWaiting");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"kCFRunLoopAfterWaiting");
break;
case kCFRunLoopExit:
NSLog(@"kCFRunLoopExit");
break;
default:
break;
}
}
- (void)viewDidLoad {
// 建立Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, observeRunLoopActicities, NULL);
// 添加Observer到RunLoop中
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
// 释放
CFRelease(observer);
}
复制代码
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 处理一些子线程的逻辑
// 回到主线程去刷新UI界面
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"11111111111");
});
});
}
复制代码
线程不会死,也能够执行
test
中的代码。可是run
方法里的end
也不会打印,由于runloop已经休眠了。因为任务永远不会执行完毕,因此哪怕是VC释放了,线程也不会释放。
- (void)viewDidLoad {
[super viewDidLoad];
self.thread = [[MJThread alloc] initWithTarget:self selector:@sel(run) obj:nil];
[self.thread start];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}
// 子线程须要执行的任务
- (void)test
{
NSLog(@"%s %@", __func__, [NSThread currentThread]);
}
- (void)run {
NSLog(@"%@----begin----", [NSThread currentThread]);
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
NSLog(@"%@----end----", [NSThread currentThread]);
}
复制代码
NSRunLoop的run方法是没法中止的,它专门用于开启一个永不销毁的线程(NSRunLoop)。
因此咱们哪怕咱们手动将runloop中止,也是作不到的。
咱们可使用另一个函数
runMode
来进行一次
runloop循环
但有一个问题是,只要该runloop被唤醒一次,就会退出
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
//[NSDate distantFuture] 会设置一个用不超时的时间
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
复制代码
经过加标记的方式,让runloop每次处理完时间,都从新runMode一次
self.thread = [[MJThread alloc] initWithBlock:^{
// 往RunLoop里面添加Source\Timer\Observer
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
while (!weakSelf.isStoped) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}];
复制代码
- (void)viewDidLoad {
[super viewDidLoad];
static int count = 0;
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"%d", ++count);
}];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
// NSDefaultRunLoopMode、UITrackingRunLoopMode才是真正存在的模式
// NSRunLoopCommonModes并非一个真的模式,它只是一个标记
// timer能在_commonModes数组中存放的模式下工做
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
复制代码
performSelector:withObject:afterDelay:
须要依赖定时器与runloop,因此在自线程中并不会起做用。
- (void)test
{
NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
NSLog(@"1");
// 这句代码的本质是往Runloop中添加定时器
[self performSelector:@selector(test) withObject:nil afterDelay:.0];
NSLog(@"3");
});
}
//打印
// 1
// 3
复制代码