runloop

runloop

作用

  • 使程序一直運行並接收用戶的輸入
  • 決定程序在何時處理哪些事件
  • 調用解耦(Message Queue)
  • 節省CPU時間(當程序啓動後,什麼都沒有執行的話,就不用讓CPU來消耗資源來執行,直接進入睡眠狀態)

模式

  • RunLoop 在同一段時間只能且必須在一種特定的模式下運行
  • 如果要更換 Mode,必須先停止當前的 Loop,然後再重新啓動 Loop
  • Mode 是保證滾動流暢的關鍵

  • NSDefaultRunLoopMode:默認狀態、空閒狀態

  • UITrackingRunLoopMode:滾動模式
  • UIInitializationRunLoopMode:私有的,App啓動時
  • NSRunLoopCommonModes:默認包含1,2兩種模式

模擬 RunLoop 實現

#import <objc/message.h>

Person *person;

void callFunc(int type) {
    NSLog(@"正在執行 %d...%@", type, person);

    UInt32 result = ((UInt32 (*)(id, SEL, int, NSString *))objc_msgSend)(person, @selector(hahaha:name:), type, @"zhangsan");
    NSLog(@"耗時 %u 秒", result);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int result = 0;
        person = [[Person alloc] init];

        while (YES) {
            printf("請輸入選擇項,0表示退出:");
            scanf("%d", &result);

            if (result == 0) {
                printf("88\n");
                break;
            } else {
                callFunc(result);
            }
        }
    }
    return 0;
}

運行循環與時鐘

@interface ViewController ()
@property (nonatomic, strong) NSTimer *timer;
@end

@implementation ViewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

- (void)fire {
    static int num = 0;

    ///  耗時操作
    for (int i = 0; i < 1000 * 1000; ++i) {
        [NSString stringWithFormat:@"hello - %d", i];
    }

    NSLog(@"%d", num++);
}

@end

運行測試,會發現卡頓非常嚴重

  • 將時鐘添加到其他線程工作
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(startTimer) object:nil];
    [self.thread start];
}

- (void)startTimer {
    @autoreleasepool {
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(fire) userInfo:nil repeats:YES];

        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

        _timerRf = CFRunLoopGetCurrent();
        CFRunLoopRun();

        NSLog(@"come here");
    }
}

注意:主線程的運行循環是默認啓動的,但是子線程的運行循環是默認不工作的,這樣能夠保證線程執行完畢後,自動被銷燬

  • 停止運行循環
- (IBAction)stop {
    if (_timerRf == NULL) {
        return;
    }

    CFRunLoopStop(_timerRf);
    _timerRf = NULL;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章