文章

运行循环


使用场景

一:让 NSTimer 正常工作,不受 UIScrollView 滚动的影响而暂停

滚动UIScrollView时,runloop的模式会被切换到UITrackingRunLoopMode,使timer的循环被暂停,滚动停止后定时器又恢复正常。若想在滚动时timer不受影响,可以把timer添加到当前线程的运行循环,并且模式为NSRunLoopCommonModes,代码如下:

1
2
3
4
5
6
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
                                                  target:self
                                                selector:@selector(test)
                                                userInfo:nil
                                                 repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];


二:性能优化

有时侯在快速滚动 tableView 时,希望滚动时不加载 cell 中的图片,滚动停止后再加载,提高界面流畅性。

示例代码:

1
2
// 拖动 UITextView 4秒以上,发现过了4秒之后,UIImageView 还没有显示图片,松开的时候,则显示图片
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"tupian"] afterDelay:4.0 inModes:@[NSDefaultRunLoopMode]];


三:让线程常驻后台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void)viewDidLoad {
    [super viewDidLoad];

    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [self.thread start];
}

- (void) run {
    // 这里写任务
    NSLog(@"----run-----");

    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

    // 添加下边两句代码,开启 RunLoop,之后 self.thread 就成了常驻线程,可随时添加任务执行
    // 注意要添加一个输入源 port
    [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    
    // [runLoop run];
    // 在实际开发中最好使用这种方式来确保 runloop 能退出,做双重的保障
    [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:(timeoutInterval + 5)]];

    // 测试是否开启了 RunLoop:如果已经开启 RunLoop,则来不了这里,因为开启了循环。
    NSLog(@"未开启RunLoop");
}
本文由作者按照 CC BY 4.0 进行授权