- RunLoop从字面意思上理解就是一个运行循环。
RunLoop的基本作用
- 保持程序的持续运行
- 处理App中的各种事件,比如 :触摸事件、定时器事件等
- 节省CPU资源,提高效率 比如:该做事做事,该休息休息
可以利用下面的伪代码演示:
int retVal = 0;
do
{
//睡眠中等待消息
int message = sleep_and_wait();
// 处理消息
retVal = process_message(message);
} while(0==retVal);
iOS中有两种方式访问Runloop
- Foundation:
NSRunLoop
- Core Foundation:
CFRunLoopRef
NSRunLoop
和CFRunLoopRef
都代表着RunLoop
对象
- 获取RunLoop对象
//获取RunLoop对象的方法
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
CFRunLoopRef runloop2 = CFRunLoopGetCurrent();
NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop];
NSLog(@"%p %p",runloop,mainRunLoop);//0x600003ba8000 0x600003ba8000
NSLog(@"%p %p"runloop2,CFRunLoopGetMain());//0x600002f08100 0x600002f08100
总结
我们可以看到两个地址是不一样的,但是通过打印输出地址和C
语言的地址是一样的,说明NSRunLoop
是对CFRunLoopRef
的包装
<CFRunLoop 0x600002590000 [0x7fff805ed4e0]>{wakeup port = 0x1d03, stopped = false, ignoreWakeUps = false,
current mode = kCFRunLoopDefaultMode,
common modes = <CFBasicHash 0x6000017936f0 [0x7fff805ed4e0]>{type = mutable set, count = 2,
entries =>
0 : <CFString 0x7fff8665f460 [0x7fff805ed4e0]>{contents = "UITrackingRunLoopMode"}
2 : <CFString 0x7fff806008e0 [0x7fff805ed4e0]>{contents = "kCFRunLoopDefaultMode"}
}
,
common mode items = <CFBasicHash 0x6000017bd680 [0x7fff805ed4e0]>{type = mutable set, count = 12,
entries =>
0 : <CFRunLoopSource 0x600002c90240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x7fff3815d9f5)}}
1 : <CFRunLoopObserver 0x600002894820 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4715bddc), context = <CFArray 0x6000017cd5f0 [0x7fff805ed4e0]>{type = mutable-small, count = 1, values = (
0 : <0x7fce34004038>
)}}
2 : <CFRunLoopObserver 0x6000028946e0 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = _afterCACommitHandler (0x7fff4718bc19), context = <CFRunLoopObserver context 0x7fce33c01930>}
3 : <CFRunLoopObserver 0x600002894640 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = _beforeCACommitHandler (0x7fff4718bbb0), context = <CFRunLoopObserver context 0x7fce33c01930>}
4 : <CFRunLoopObserver 0x600002894780 [0x7fff805ed4e0]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4715bddc), context = <CFArray 0x6000017cd5f0 [0x7fff805ed4e0]>{type = mutable-small, count = 1, values = (
0 : <0x7fce34004038>
)}}
9 : <CFRunLoopSource 0x600002c98000 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x3003, callout = PurpleEventCallback (0x7fff3815da01)}}
10 : <CFRunLoopSource 0x600002c9cfc0 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 41731, subsystem = 0x7fff81eccfc8, context = 0x600003d8c360}}
12 : <CFRunLoopObserver 0x60000289caa0 [0x7fff805ed4e0]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = _UIGestureRecognizerUpdateObserver (0x7fff46d134c2), context = <CFRunLoopObserver context 0x60000329d490>}
15 : <CFRunLoopObserver 0x60000289c8c0 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv (0x7fff2afc03ce), context = <CFRunLoopObserver context 0x0>}
16 : <CFRunLoopSource 0x600002c943c0 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x600002c98180, callout = __handleEventQueue (0x7fff471f5095)}}
17 : <CFRunLoopSource 0x600002c94300 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x6000017be4f0, callout = __handleHIDEventFetcherDrain (0x7fff471f50a1)}}
18 : <CFRunLoopSource 0x600002c94240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x600003d8c540, callout = FBSSerialQueueRunLoopSourceHandler (0x7fff36330576)}}
}
,
modes = <CFBasicHash 0x6000017937b0 [0x7fff805ed4e0]>{type = mutable set, count = 4,
entries =>
2 : <CFRunLoopMode 0x600002298340 [0x7fff805ed4e0]>{name = UITrackingRunLoopMode, port set = 0x5203, queue = 0x60000379c980, source = 0x60000379ca80 (not fired), timer port = 0x2d03,
sources0 = <CFBasicHash 0x6000017bd6e0 [0x7fff805ed4e0]>{type = mutable set, count = 4,
entries =>
0 : <CFRunLoopSource 0x600002c90240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x7fff3815d9f5)}}
1 : <CFRunLoopSource 0x600002c943c0 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x600002c98180, callout = __handleEventQueue (0x7fff471f5095)}}
2 : <CFRunLoopSource 0x600002c94240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x600003d8c540, callout = FBSSerialQueueRunLoopSourceHandler (0x7fff36330576)}}
3 : <CFRunLoopSource 0x600002c94300 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x6000017be4f0, callout = __handleHIDEventFetcherDrain (0x7fff471f50a1)}}
}
,
sources1 = <CFBasicHash 0x6000017bd710 [0x7fff805ed4e0]>{type = mutable set, count = 2,
entries =>
0 : <CFRunLoopSource 0x600002c98000 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x3003, callout = PurpleEventCallback (0x7fff3815da01)}}
1 : <CFRunLoopSource 0x600002c9cfc0 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 41731, subsystem = 0x7fff81eccfc8, context = 0x600003d8c360}}
}
,
observers = (
"<CFRunLoopObserver 0x600002894780 [0x7fff805ed4e0]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4715bddc), context = <CFArray 0x6000017cd5f0 [0x7fff805ed4e0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fce34004038>\n)}}",
"<CFRunLoopObserver 0x60000289caa0 [0x7fff805ed4e0]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = _UIGestureRecognizerUpdateObserver (0x7fff46d134c2), context = <CFRunLoopObserver context 0x60000329d490>}",
"<CFRunLoopObserver 0x600002894640 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = _beforeCACommitHandler (0x7fff4718bbb0), context = <CFRunLoopObserver context 0x7fce33c01930>}",
"<CFRunLoopObserver 0x60000289c8c0 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv (0x7fff2afc03ce), context = <CFRunLoopObserver context 0x0>}",
"<CFRunLoopObserver 0x6000028946e0 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = _afterCACommitHandler (0x7fff4718bc19), context = <CFRunLoopObserver context 0x7fce33c01930>}",
"<CFRunLoopObserver 0x600002894820 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4715bddc), context = <CFArray 0x6000017cd5f0 [0x7fff805ed4e0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fce34004038>\n)}}"
),
timers = <CFArray 0x600003d88540 [0x7fff805ed4e0]>{type = mutable-small, count = 0, values = ()},
currently 592493202 (132206778385536) / soft deadline in: 1.84466119e+10 sec (@ -1) / hard deadline in: 1.84466119e+10 sec (@ -1)
},
3 : <CFRunLoopMode 0x600002298410 [0x7fff805ed4e0]>{name = GSEventReceiveRunLoopMode, port set = 0x2e03, queue = 0x60000379cb00, source = 0x60000379cc00 (not fired), timer port = 0x4f03,
sources0 = <CFBasicHash 0x6000017bd830 [0x7fff805ed4e0]>{type = mutable set, count = 1,
entries =>
0 : <CFRunLoopSource 0x600002c90240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x7fff3815d9f5)}}
}
,
sources1 = <CFBasicHash 0x6000017bd650 [0x7fff805ed4e0]>{type = mutable set, count = 1,
entries =>
0 : <CFRunLoopSource 0x600002c98240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x3003, callout = PurpleEventCallback (0x7fff3815da01)}}
}
,
observers = (null),
timers = (null),
currently 592493202 (132206780901271) / soft deadline in: 1.84466119e+10 sec (@ -1) / hard deadline in: 1.84466119e+10 sec (@ -1)
},
4 : <CFRunLoopMode 0x600002290340 [0x7fff805ed4e0]>{name = kCFRunLoopDefaultMode, port set = 0x1e03, queue = 0x600003790c80, source = 0x600003790d80 (not fired), timer port = 0x2303,
sources0 = <CFBasicHash 0x6000017bd740 [0x7fff805ed4e0]>{type = mutable set, count = 4,
entries =>
0 : <CFRunLoopSource 0x600002c90240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x7fff3815d9f5)}}
1 : <CFRunLoopSource 0x600002c943c0 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x600002c98180, callout = __handleEventQueue (0x7fff471f5095)}}
2 : <CFRunLoopSource 0x600002c94240 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x600003d8c540, callout = FBSSerialQueueRunLoopSourceHandler (0x7fff36330576)}}
3 : <CFRunLoopSource 0x600002c94300 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x6000017be4f0, callout = __handleHIDEventFetcherDrain (0x7fff471f50a1)}}
}
,
sources1 = <CFBasicHash 0x6000017bd800 [0x7fff805ed4e0]>{type = mutable set, count = 2,
entries =>
0 : <CFRunLoopSource 0x600002c98000 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x3003, callout = PurpleEventCallback (0x7fff3815da01)}}
1 : <CFRunLoopSource 0x600002c9cfc0 [0x7fff805ed4e0]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 41731, subsystem = 0x7fff81eccfc8, context = 0x600003d8c360}}
}
,
observers = (
"<CFRunLoopObserver 0x600002894780 [0x7fff805ed4e0]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4715bddc), context = <CFArray 0x6000017cd5f0 [0x7fff805ed4e0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fce34004038>\n)}}",
"<CFRunLoopObserver 0x60000289caa0 [0x7fff805ed4e0]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = _UIGestureRecognizerUpdateObserver (0x7fff46d134c2), context = <CFRunLoopObserver context 0x60000329d490>}",
"<CFRunLoopObserver 0x600002894640 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = _beforeCACommitHandler (0x7fff4718bbb0), context = <CFRunLoopObserver context 0x7fce33c01930>}",
"<CFRunLoopObserver 0x60000289c8c0 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv (0x7fff2afc03ce), context = <CFRunLoopObserver context 0x0>}",
"<CFRunLoopObserver 0x6000028946e0 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = _afterCACommitHandler (0x7fff4718bc19), context = <CFRunLoopObserver context 0x7fce33c01930>}",
"<CFRunLoopObserver 0x600002894820 [0x7fff805ed4e0]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x7fff4715bddc), context = <CFArray 0x6000017cd5f0 [0x7fff805ed4e0]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fce34004038>\n)}}"
),
timers = <CFArray 0x600003d9e520 [0x7fff805ed4e0]>{type = mutable-small, count = 0, values = ()},
currently 592493202 (132206780976526) / soft deadline in: 1.84466119e+10 sec (@ -1) / hard deadline in: 1.84466119e+10 sec (@ -1)
},
5 : <CFRunLoopMode 0x60000229ee50 [0x7fff805ed4e0]>{name = kCFRunLoopCommonModes, port set = 0xa603, queue = 0x600003799580, source = 0x600003799600 (not fired), timer port = 0xa403,
sources0 = (null),
sources1 = (null),
observers = (null),
timers = (null),
currently 592493202 (132206782855209) / soft deadline in: 1.84466119e+10 sec (@ -1) / hard deadline in: 1.84466119e+10 sec (@ -1)
},
}
}
- RunLoop与线程的关系
1. 每个线程都有唯一的一个与之对应的RunLoop对象
2. RunLoop保存在一个全局的Dictionary里,线程作为Key,Runloop作为value
3.线程刚创建的时候并没有RunLoop对象,RunLoop会在第一次获取它时创建
4.RunLoop会在线程结束时销毁
5.主线程的RunLoop已经自动获取(创建)子线程默认没有开启RunLoop
- 与RunLoop相关的类
- CFRunLoopRef
- CFRunLoopModeRef
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
- 我们可以通查看RunLoop源码看到
RunLoop
的底层结构[如下所示]
我们可以看到上图RunLoop
内部含有pthread
线程以及Set
集合的_modes
说明一个RunLoop中有多种模式,但是只有一个为当前模式查看CFRunLoopMode如下
CFRunLoopModeRef
代表RunLoop
的运行模式
一个RunLoop
包含若干个Mode
,每个Mode
又包含若干个Source0/Source1/Timer/Observer
RunLoop
启动时只能选择其中一个Mode
,作为currentMode
如果需要切换Mode
,只能退出当前Loop
,再重新选择一个Mode
进入 不同组的Source0/Source1/Timer/Observer
能分隔开来,互补影响,如果Mode
里没有任何Source0/Source1/Timer/Observer,RunLoop
会立马退出
- CFRunLoopModeRef常见的两种Mode
1.
kCGRunLoopDefaultMode(NSDefaultRunLoopMode):App
的默认Mode
,通常主线程是在这种Mode
下运行
2.UITrackingRunLoopMode
:界面跟踪Mode
,用于ScrollView
追踪触摸滑动,保证界面滑动时不受其他Mode
的影响
- 下面研究Mode的内容:
1. Source0:
触摸事件处理
performSelector:onThread
我们利用touchesBegan
方法打断点查看函数调用栈信息;
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
- 在控制台输入
bt
(breakpoint trace)
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000010b5be75d RunLoop`-[RunLoopBasicVC touchesBegan:withEvent:](self=0x00007fb6ea4172b0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000000dc6e0) at RunLoopBasicVC.m:33:5
frame #1: 0x00007fff4718f0bf UIKitCore`forwardTouchMethod + 340
frame #2: 0x00007fff4718ef5a UIKitCore`-[UIResponder touchesBegan:withEvent:] + 49
frame #3: 0x00007fff4719df3e UIKitCore`-[UIWindow _sendTouchesForEvent:] + 1867
frame #4: 0x00007fff4719fb26 UIKitCore`-[UIWindow sendEvent:] + 4596
frame #5: 0x00007fff4717b1a7 UIKitCore`-[UIApplication sendEvent:] + 356
frame #6: 0x00007fff471faa18 UIKitCore`__dispatchPreprocessedEventFromEventQueue + 6847
frame #7: 0x00007fff471fd4de UIKitCore`__handleEventQueueInternal + 5980
frame #8: 0x00007fff23afbac1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #9: 0x00007fff23afb9ec CoreFoundation`__CFRunLoopDoSource0 + 76
frame #10: 0x00007fff23afb1c4 CoreFoundation`__CFRunLoopDoSources0 + 180
frame #11: 0x00007fff23af5ecf CoreFoundation`__CFRunLoopRun + 1263
frame #12: 0x00007fff23af56b6 CoreFoundation`CFRunLoopRunSpecific + 438
frame #13: 0x00007fff3815cbb0 GraphicsServices`GSEventRunModal + 65
* frame #14: 0x00007fff47162a67 UIKitCore`UIApplicationMain + 1621
frame #15: 0x000000010b5bea24 RunLoop`main(argc=1, argv=0x00007ffee4640cf8) at main.m:18:12
frame #16: 0x00007fff5123bcf5 libdyld.dylib`start + 1
frame #17: 0x00007fff5123bcf5 libdyld.dylib`start + 1
(lldb)
我们看到调用__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
看到Source0
处理触摸事件,performSelector:onThread
也是由Source0
处理
2.Source1
基于Port的线程间通信
系统事件的捕捉(也就是说通过Source1
捕捉,然后分发到Source0
里面处理的)
3.Timers
NSTimer
performSelector:withObject:afterDelay:
4.Observers
用于监听RunLoop的状态
UI刷新(BeforeWaiting)
Autorelease pool
-
CFRunLoopObserverRef
的状态
-我们自己添加RunLoop的状态监听来查看它是如何工作的
// 观察方法
void observeRunLoopActivites(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"kCFRunLoopEntry");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"kCFRunLoopBeforeTimers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"kCFRunLoopBeforeSources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"kCFRunLoopBeforeWaiting");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"kCFRunLoopAfterWaiting");
break;
case kCFRunLoopExit:
NSLog(@"kCFRunLoopExit");
break;
default:
break;
}
}
//--------------
//创建Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreate( kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, observeRunLoopActivites, NULL);
//添加监听者到RunLoop中 通用模式(包含kCFRunLoopDefaultMode和 UITrackingRunLoopMode)
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
//释放observer
CFRelease(observer);
//创建方式二
CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
//直接使用block处理
});
- 再次调用
touchesBegan
方法
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
得到如下的输出:
2019-10-11 22:22:33.054255+0800 RunLoop[93336:1305548] kCFRunLoopAfterWaiting
2019-10-11 22:22:33.054488+0800 RunLoop[93336:1305548] kCFRunLoopBeforeTimers
2019-10-11 22:22:33.054584+0800 RunLoop[93336:1305548] kCFRunLoopBeforeSources
2019-10-11 22:22:33.056189+0800 RunLoop[93336:1305548] -[RunLoopBasicVC touchesBegan:withEvent:]
2019-10-11 22:22:33.056511+0800 RunLoop[93336:1305548] kCFRunLoopBeforeTimers
2019-10-11 22:22:33.056858+0800 RunLoop[93336:1305548] kCFRunLoopBeforeSources
2019-10-11 22:22:33.058080+0800 RunLoop[93336:1305548] kCFRunLoopBeforeTimers
2019-10-11 22:22:33.058711+0800 RunLoop[93336:1305548] kCFRunLoopBeforeSources
2019-10-11 22:22:33.060141+0800 RunLoop[93336:1305548] kCFRunLoopBeforeTimers
2019-10-11 22:22:33.061535+0800 RunLoop[93336:1305548] kCFRunLoopBeforeSources
2019-10-11 22:22:33.063411+0800 RunLoop[93336:1305548] kCFRunLoopBeforeTimers
2019-10-11 22:22:33.063973+0800 RunLoop[93336:1305548] kCFRunLoopBeforeSources
2019-10-11 22:22:33.064541+0800 RunLoop[93336:1305548] kCFRunLoopBeforeWaiting
2019-10-11 22:22:35.063183+0800 RunLoop[93336:1305548] kCFRunLoopAfterWaiting
2019-10-11 22:22:35.063707+0800 RunLoop[93336:1305548] kCFRunLoopBeforeTimers
2019-10-11 22:22:35.065788+0800 RunLoop[93336:1305548] kCFRunLoopBeforeSources
2019-10-11 22:22:35.066229+0800 RunLoop[93336:1305548] kCFRunLoopBeforeWaiting
2019-10-11 22:22:35.066682+0800 RunLoop[93336:1305548] kCFRunLoopAfterWaiting
2019-10-11 22:22:35.067281+0800 RunLoop[93336:1305548] kCFRunLoopBeforeTimers
2019-10-11 22:22:35.067672+0800 RunLoop[93336:1305548] kCFRunLoopBeforeSources
2019-10-11 22:22:35.067815+0800 RunLoop[93336:1305548] kCFRunLoopBeforeWaiting
我们可以看到确实是Sources
状态下处理touchesBegan
方法
再次编写定时器代码
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// NSLog(@"%s",__func__);
[NSTimer scheduledTimerWithTimeInterval:3 repeats:NO block:^(NSTimer * _Nonnull timer) {
NSLog(@"随风流年--定时器");
}];
}
22:30:23.829237+0800 RunLoop[93381:1310752] kCFRunLoopBeforeWaiting
22:30:26.026510+0800 RunLoop[93381:1310752] kCFRunLoopAfterWaiting
22:30:26.026815+0800 RunLoop[93381:1310752] kCFRunLoopBeforeTimers
22:30:26.027012+0800 RunLoop[93381:1310752] kCFRunLoopBeforeSources
22:30:26.027206+0800 RunLoop[93381:1310752] kCFRunLoopBeforeWaiting
22:30:26.027431+0800 RunLoop[93381:1310752] kCFRunLoopAfterWaiting
22:30:26.027608+0800 RunLoop[93381:1310752] kCFRunLoopBeforeTimers
22:30:26.027763+0800 RunLoop[93381:1310752] kCFRunLoopBeforeSources
22:30:26.027924+0800 RunLoop[93381:1310752] kCFRunLoopBeforeWaiting
22:30:26.796064+0800 RunLoop[93381:1310752] kCFRunLoopAfterWaiting
22:30:26.796507+0800 RunLoop[93381:1310752] 随风流年--定时器
22:30:26.796797+0800 RunLoop[93381:1310752] kCFRunLoopBeforeTimers
22:30:26.797004+0800 RunLoop[93381:1310752] kCFRunLoopBeforeSources
22:30:26.797196+0800 RunLoop[93381:1310752] kCFRunLoopBeforeWaiting
- 模式的切换
//创建方式二
CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
//直接使用block处理
switch (activity) {
case kCFRunLoopEntry:
{
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent()); NSLog(@"kCFRunLoopEntry--%@",mode);
CFRelease(mode);
break;
}
case kCFRunLoopExit:{
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent()); NSLog(@"kCFRunLoopExit --%@",mode);
CFRelease(mode);
break;
}
default:
break;
}
});
如果我们滚动表单时会打印输出kCFRunLoopDefaultMode
和UITrackingRunLoopMode
的来回切换
RunLoop在实际开发中的应用
- 控制线程的声明周期
- 解决NSTimer在滑动时停止工作的问题
- 监控应用卡顿
- 性能优化
- 如果我们编写定时器代码如下:
static int count = 0;
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"count=%d----%@",++count,CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent()));
}];
在滚动列表的时候就定时器的Mode
就会切换,这样定时器(timer)
就不会继续执行了,那么该怎么办?
可以自己定义Mode
下的timer
操作
static int count = 0;
//自己添加模式
NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"count=%d----%@",++count,CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent()));
}];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
15:00:52.325695+0800 RunLoop[982:53172] count=1----kCFRunLoopDefaultMode
15:00:53.325723+0800 RunLoop[982:53172] count=2----kCFRunLoopDefaultMode
15:00:54.325496+0800 RunLoop[982:53172] count=3----kCFRunLoopDefaultMode
但是这样写同样有问题?那就是定时器Timer
停不下来了,怎么办?
如何让线程停下来?需要使用的时候开启?不需要使用的时候,停下来呢?
接下来继续 go on
//
// SFPermenantThread.h
// NStimer失效
//
// Created by 随风流年 on 2019/9/6.
// Copyright © 2019 随风流年. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef void (^SFPermenantThreadTask)(void);
NS_ASSUME_NONNULL_BEGIN
@interface SFPermenantThread : NSObject
/*
开启一个线程
*/
-(void)run;
//执行一个任务
//-(void)executeTaskWithTarget:(id)target action:(SEL)action object:(id)object;
-(void)executeTaskWithBlock:(SFPermenantThreadTask)task;
/*
结束一个线程
*/
-(void)stop;
@end
NS_ASSUME_NONNULL_END
.m 的实现文件如下:
//
// SFPermenantThread.m
// NStimer失效
//
// Created by 随风流年 on 2019/9/6.
// Copyright © 2019 随风流年. All rights reserved.
//
#import "SFPermenantThread.h"
@interface SFThread : NSThread
@end
@implementation SFThread
-(void)dealloc{
NSLog(@"%s",__func__);
}
@end
/** SFPermenantThread **/
@interface SFPermenantThread()
@property (strong,nonatomic) SFThread *innerThread;
@property (nonatomic, assign, getter=isStopped) BOOL stopped;
@end
@implementation SFPermenantThread
- (instancetype)init{
if (self = [super init]) {
self.stopped = NO;
__weak typeof(self) weakSelf = self;
self.innerThread = [[SFThread alloc]initWithBlock:^{
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc]init] forMode:NSDefaultRunLoopMode];
while (weakSelf && !weakSelf.stopped) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}];
}
return self;
}
-(void)run{
if (!self.innerThread) {
return;
}
[self.innerThread start];
}
-(void)executeTaskWithBlock:(SFPermenantThreadTask)task{
if (!self.innerThread || !task) return;
[self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:task waitUntilDone:NO];
}
-(void)stop{
if (!self.innerThread) return;
[self performSelector:@selector(__stop) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}
#pragma mark -- private method ---
-(void)__stop
{
self.stopped = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
self.innerThread = nil;
}
-(void)__executeTask:(SFPermenantThreadTask)task{
task();
}
@end