在Cocoa中,每个线程(NSThread)对象中内部都有一个run
loop(NSRunLoop)对象用来循环处理输入事件,处理的事件包括两类,一是来自Input sources的异步事件,一是来自Timer
sources的同步事件;
run Loop在处理输入事件时会产生通知,可以通过Core Foundation向线程中添加run-loop
observers来监听特定事件,以在监听的事件发生时做附加的处理工作。
每个run
loop可运行在不同的模式下,一个run loop mode是一个集合,其中包含其监听的若干输入事件源,定时器,以及在事件发生时需要通知的run loop
observers。运行在一种mode下的run loop只会处理其run loop mode中包含的输入源事件,定时器事件,以及通知run loop
mode中包含的observers。
Cocoa中的预定义模式有:
获取当前线程的run loop mode
NSString* runLoopMode = [[NSRunLoop currentRunLoop] currentMode];
NSTimer与NSURLConnection默认运行在default
mode下,这样当用户在拖动UITableView处于UITrackingRunLoopMode模式时,NSTimer不能fire,NSURLConnection的数据也无法处理。
NSTimer的例子:
在一个UITableViewController中启动一个0.2s的循环定时器,在定时器到期时更新一个计数器,并显示在label上。
-(void)viewDidLoad
{
label =[[[UILabel alloc]initWithFrame:CGRectMake(10, 100, 100, 50)]autorelease];
[self.view addSubview:label];
count = 0;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval: 1
target: self
selector: @selector(incrementCounter:)
userInfo: nil
repeats: YES];
}
- (void)incrementCounter:(NSTimer *)theTimer
{
count++;
label.text = [NSString stringWithFormat:@"%d",count];
}
在正常情况下,可看到每隔0.2s,label上显示的数字+1,但当你拖动或按住tableView时,label上的数字不再更新,当你手指离开时,label上的数字继续更新。当你拖动UItableView时,当前线程run
loop处于UIEventTrackingRunLoopMode模式,在这种模式下,不处理定时器事件,即定时器无法fire,label上的数字也就无法更新。
解决方法,一种方法是在另外的线程中处理定时器事件,可把Timer加入到NSOperation中在另一个线程中调度;还有一种方法时修改Timer运行的run loop模式,将其加入到UITrackingRunLoopMode模式或NSRunLoopCommonModes模式中。
即
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
或
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NSURLConnection也是如此,见SDWebImage中的描述,以及SDWebImageDownloader.m代码中的实现。修改NSURLConnection的运行模式可使用scheduleInRunLoop:forMode:方法。
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]autorelease];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
中
同事有两个 事件同时发生,一个是 监听触摸事件,一个 时间时间,timer,
曾经 那个抽奖的,原来如此,加个新的线程,或者 改下 主线程的 runloop 模式,
原文:http://www.cnblogs.com/guligei/p/3512476.html