我们的项目其实就是一个RunLoop,比如main函数的UIApplicationMain就是一个死循环函数,它在不停的询问是否有事件发生,比如我在main函数里这样写:
int main(int argc, char * argv[]) {
@autoreleasepool {
NSLog(@"%@",[NSThread currentThread]);
//UIApplicationMain 死循环 -- Runloop循环
int a = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
NSLog(@"来了没");
return a;
}
}
2018-06-21 17:10:56.622877+0800 001--Runloop1[752:290434] <NSThread: 0x1d0075280>{number = 1, name = main}
最后我只得到了第一次打印,证明程序在UIApplicationMain函数进入了死循环,所以没有走到我的第二次打印
1、RunLoop的作用
- 保住当前线程的生命
- 监听事件:触摸,网络,时钟
2、RunLoop的几种运行模式
NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
//timer添加到Runloop中!!
//NSDefaultRunLoopMode 默认模式,如果UI有操作时,runloop会暂停
//UITrackingRunLoopMode UI模式,当UI上有滑动等操作时才会运行,否则暂停
//NSRunLoopCommonModes 占位模式!!UI&&默认!,在前两种模式下都会运行
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
- (void)timerMethod {
NSLog(@"%@--跑起来!!",[NSThread currentThread]);
}
通过打印就可以看出他们的区别,自己验证一下吧,比如放一个scrollView,比较滑动和不滑动时几种模式的不同。
3、用RunLoop保住线程的生命
如果不想RunLoop受到UI操作的影响,我们可以把他放到子线程里去执行
NSThread * thread = [[NSThread alloc] initWithBlock:^{
NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0001]];
NSLog(@"走起");
}];
[thread start];
但是这时候发现,只有“走起”被打印了,timer的timerMethod并没有执行,这是因为thread里的代码执行完之后thread就销毁了,我们自定义一个继承自NSThread的类,然后实现它的dealloc
方法,可以发现它被销毁了
-(void)dealloc
{
NSLog(@"线程挂了");
}
2018-06-21 18:03:53.979368+0800 001--Runloop1[767:305273] 走起
2018-06-21 18:03:53.979485+0800 001--Runloop1[767:305273] 线程挂了
到这个你可能会说,让控制器强引用它不就完了吗?
但是并不行,因为这样OC的对象被留住了,但是底层的线程还是被释放了,那怎么才能保住当前线程的生命呢?
答案是让线程有执行不完的任务!!!
NSThread * thread = [[NSThread alloc] initWithBlock:^{
NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
while (true) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0001]];
}
NSLog(@"走起");
}];
[thread start];
这时候发现,timerMethod方法被循环的调用起来了。我们把while的条件换成变量以后,运行过程把true变成f'alse,会发现RunLoop会停止,线程会销毁。
4、线程间的通讯
NSThread * thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"-----%@",[NSThread currentThread]);
[[NSRunLoop currentRunLoop] run];
}];
[thread start];
[self performSelector:@selector(subThreadMethod) onThread:thread withObject:nil waitUntilDone:NO];
-(void)subThreadMethod{
NSLog(@"subThreadMethod --- %@",[NSThread currentThread]);
}
在主线程给子线程添加执行代码。
网友评论