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;
}