runloop中将一个任务放到第二次runloop中执行:利用socket/port做一些事情(封装一个source)
最简单的方法就是
[self performSelector:@selector(xxxxx) withObject:nil afterDelay:0];
进行了以下的实验
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self observer];
[self performSelector:@selector(testPerformSelectorAfterDelay) withObject:nil afterDelay:3];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)testPerformSelectorAfterDelay {
[self performSelector:@selector(printMyName) withObject:nil afterDelay:0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"dispatch_after 0");
});
dispatch_async(dispatch_get_main_queue(),^{
NSLog(@"dispatch_async 0");
});
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
NSLog(@"CFRunLoopPerformBlock 0");
});
for (int i=0; i < 10; i++) {
NSLog(@"index is %d", i);
}
}
- (void)printMyName {
NSLog(@"performSelector after 0");
}
-(void)observer{
//创建一个监听对象
/*
第一个参数:分配存储空间的
第二个参数:要监听的状态 kCFRunLoopAllActivities 所有状态
第三个参数:是否要持续监听
第四个参数:优先级
第五个参数:回调
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"runloop进入");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"runloop要去处理timer");
break;
case kCFRunLoopBeforeSources:
NSLog(@"runloop要去处理Sources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"runloop要睡觉了");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"runloop醒来啦");
break;
case kCFRunLoopExit:
NSLog(@"runloop退出");
break;
default:
break;
}
});
//给runloop添加监听者
/*
第一个参数:要监听哪个runloop
第二个参数:监听者
第三个参数:要监听runloop在哪种运行模式下的状态
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
// [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(run1) userInfo:nil repeats:YES];
CFRelease(observer);
}
- (void)run1 {
NSLog(@"run1 run");
}
2018-05-24 12:09:00.671223+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.671392+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.671551+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.671652+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.671801+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.671907+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.672612+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.672976+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.673119+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.674094+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.675117+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.675293+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.675401+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.675769+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.676426+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:00.777952+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:00.780101+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.781568+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.782029+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.782173+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.786887+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.788580+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.791220+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.792284+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.793257+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.795218+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.796139+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:01.073130+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:01.074644+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:01.075867+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:01.076606+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:02.034410+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:02.035123+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:02.035260+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:02.035395+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:03.646095+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:03.646415+0800 RunLoopDemo[9662:6893911] index is 0
2018-05-24 12:09:03.646521+0800 RunLoopDemo[9662:6893911] index is 1
2018-05-24 12:09:03.646640+0800 RunLoopDemo[9662:6893911] index is 2
2018-05-24 12:09:03.646814+0800 RunLoopDemo[9662:6893911] index is 3
2018-05-24 12:09:03.647089+0800 RunLoopDemo[9662:6893911] index is 4
2018-05-24 12:09:03.647174+0800 RunLoopDemo[9662:6893911] index is 5
2018-05-24 12:09:03.647284+0800 RunLoopDemo[9662:6893911] index is 6
2018-05-24 12:09:03.647372+0800 RunLoopDemo[9662:6893911] index is 7
2018-05-24 12:09:03.647471+0800 RunLoopDemo[9662:6893911] index is 8
2018-05-24 12:09:03.647588+0800 RunLoopDemo[9662:6893911] index is 9
2018-05-24 12:09:03.647673+0800 RunLoopDemo[9662:6893911] CFRunLoopPerformBlock 0
2018-05-24 12:09:03.647824+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:03.647923+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:03.648123+0800 RunLoopDemo[9662:6893911] dispatch_after 0
2018-05-24 12:09:03.648332+0800 RunLoopDemo[9662:6893911] dispatch_async 0
2018-05-24 12:09:03.648635+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:03.648903+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:03.649115+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:03.649400+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:03.649651+0800 RunLoopDemo[9662:6893911] performSelector after 0
2018-05-24 12:09:03.649862+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:03.650043+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:03.650312+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
通过log可以发现,只有
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
会在下一个runloop中调用,GCD的并不一定会在下一个,GCD只是追加到队列中,如果当前runloop没休眠,就会直接运行。
while (true) {
Call kCFRunLoopBeforeTimers observer callbacks;
Call kCFRunLoopBeforeSources observer callbacks;
Perform blocks queued by CFRunLoopPerformBlock;
Call the callback of each version 0 CFRunLoopSource that has been signalled;
if (any version 0 source callbacks were called) {
Perform blocks newly queued by CFRunLoopPerformBlock;
}
if (I didn't drain the main queue on the last iteration
AND the main queue has any blocks waiting)
{
while (main queue has blocks) {
perform the next block on the main queue
}
} else {
Call kCFRunLoopBeforeWaiting observer callbacks;
Wait for a CFRunLoopSource to be signalled
OR for a timer to fire
OR for a block to be added to the main queue;
Call kCFRunLoopAfterWaiting observer callbacks;
if (the event was a timer) {
call CFRunLoopTimer callbacks for timers that should have fired by now
} else if (event was a block arriving on the main queue) {
while (main queue has blocks) {
perform the next block on the main queue
}
} else {
look up the version 1 CFRunLoopSource for the event
if (I found a version 1 source) {
call the source's callback
}
}
}
Perform blocks queued by CFRunLoopPerformBlock;
}
详情见https://stackoverflow.com/a/15168471
YYText监听runloop休眠和退出前去完成一些UI任务。
static void YYRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
if (transactionSet.count == 0) return;
NSSet *currentSet = transactionSet;
transactionSet = [NSMutableSet new];
[currentSet enumerateObjectsUsingBlock:^(YYTextTransaction *transaction, BOOL *stop) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[transaction.target performSelector:transaction.selector];
#pragma clang diagnostic pop
}];
}
static void YYTextTransactionSetup() {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
transactionSet = [NSMutableSet new];
CFRunLoopRef runloop = CFRunLoopGetMain();
CFRunLoopObserverRef observer;
observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(),
kCFRunLoopBeforeWaiting | kCFRunLoopExit,
true, // repeat
0xFFFFFF, // after CATransaction(2000000)
YYRunLoopObserverCallBack, NULL);
CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes);
CFRelease(observer);
});
}
网友评论