什么是runLoop
NSRunLoop是消息机制的处理模式
NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠
NSTimer默认添加到当前NSRunLoop中,也可以手动制定添加到自己新建的NSRunLoop
NSRunLoop就是一直在循环检测,从线程start到线程end,检测inputsource(如点击,双击等操作)同步事件,检测timesource同步事件,检测到输入源会执行处理函数,首先会产生通知,corefunction向线程添加runloop observers来监听事件,意在监听事件发生时来做处理。
在单线程的app中,不需要注意Run Loop,但不代表没有。程序启动时,系统已经在主线程中加入了Run Loop。它保证了我们的主线程在运行起来后,就处于一种“等待”的状态(而不像一些命令行程序一样运行一次就结束了),这个时候如果有接收到的事件(Timer的定时到了或是其他线程的消息),就会执行任务,否则就处于休眠状态。
runloopmode是一个集合,包括监听:事件源,定时器,以及需通知的runloop observers
模式包括:
default模式:几乎包括所有输入源(除NSConnection) NSDefaultRunLoopMode模式
mode模式:处理modal panels
connection模式:处理NSConnection事件,属于系统内部,用户基本不用
event tracking模式:如组件拖动输入源 UITrackingRunLoopModes 不处理定时事件
common modes模式:NSRunLoopCommonModes 这是一组可配置的通用模式。将input sources与该模式关联则同时也将input sources与该组中的其它模式进行了关联。
每次运行一个run loop,你指定(显式或隐式)run loop的运行模式。当相应的模式传递给run loop时,只有与该模式对应的input sources才被监控并允许run loop对事件进行处理(与此类似,也只有与该模式对应的observers才会被通知)
//广告业
例:
1).在timer与table同时执行情况,当拖动table时,runloop进入UITrackingRunLoopModes模式下,不会处理定时事件,此时timer不能处理,所以此时将timer加入到NSRunLoopCommonModes模式(addTimer forMode)
2).在scroll一个页面时来松开,此时connection不会收到消息,由于scroll时runloop为UITrackingRunLoopModes模式,不接收输入源,此时要修改connection的mode
[scheduleInRunLoop:[NSRunLoop currentRunLoop]forMode:NSRunLoopCommonModes];
A.Timer和scrollView一起使用的时候,如果一直滚动scrollView 此时 timer的事件将不会处理
解决方案:1.将timer添加到指定的RunLoopMode中
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
2.创建子线程 把timer放到子线程的RunLoop中
B.子线程实现异步下载
Demo
@implementation ViewController
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.UIScrollView *table = [[UIScrollView alloc] initWithFrame:self.view.bounds];
for (NSInteger i = 0; i < 3; i++) {
UIView view = [[UIView alloc] initWithFrame:CGRectMake(i 375, 0, 375, 667)];view.backgroundColor = [UIColor colorWithRed:arc4random() % 256 / 255.0f green:arc4random() % 256 / 255.0f blue:arc4random() % 256 / 255.0f alpha:1.0f]; [table addSubview:view];
}
table.contentSize = CGSizeMake( 3 * 375, 667);
[self.view addSubview:table];
//将timer添加到指定的RunLoopMode中 NSRunLoopCommonModes
//[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];//2.把timer放到子线程
[NSThread detachNewThreadSelector:@selector(createThread) toTarget:self withObject:nil];
}
-(void)createThread
{
if 0
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
//创建一个 runLoop对象 并且开启runLoop
[[NSRunLoop currentRunLoop] run];
endif
//子线程里 开启异步
NSString *string = @"http://www.baidu.com";
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:string]] delegate:self];
//[[NSRunLoop currentRunLoop] run];
while (!self.isFinish) {
NSLog(@"123");
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
-(void)connection:(NSURLConnection )connection didReceiveResponse:(NSURLResponse )response
{
NSLog(@”%@”,NSStringFromSelector(_cmd));
}
-(void)connection:(NSURLConnection )connection didFailWithError:(NSError )error
{
NSLog(@”%@”,NSStringFromSelector(_cmd));
}
-(void)connection:(NSURLConnection )connection didReceiveData:(NSData )data
{
NSLog(@”%@”,NSStringFromSelector(_cmd));
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@”%@”,NSStringFromSelector(_cmd));
self.isFinish = YES;
}
-(void)timeChange
{
NSLog(@”123”);
}
main.m
int main(int argc, char * argv[]) {
@autoreleasepool {
//点击事件 InputEvent
//timer TimerEvent
//Oberveser KVO connection
// while (1) {
//
// }
//NSRunLoop
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}