1.load方法下邊為什么建議加上dispatch-once?
雖然load方法只調(diào)用一次,可能某些情況下回顯示調(diào)用load,這樣dispatch-once里的代碼也會(huì)執(zhí)行一次。
bt = breakpoint trace
2.Runloop與線程
Runloop保存在一個(gè)全局的Dictionary里,線程做為key,Runloop作為value;
Runloop會(huì)在線程結(jié)束時(shí)銷(xiāo)毀。
3.runloop數(shù)據(jù)結(jié)構(gòu)是什么樣子的?
struct __CFRunLoop {
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems; //放了_commonModes運(yùn)行的timer等
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
};
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFStringRef _name;
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
};
4.源碼分析runloop執(zhí)行流程:
touchbegan中斷點(diǎn)bt一下找到CFRunLoopRunSpecific,然后__CFRunLoopRun:
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
int32_t retVal = 0;
do {
//通知Observers:即將處理Timers
if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
//通知Observers:即將處理Sources
if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
//處理blocks
__CFRunLoopDoBlocks(rl, rlm);
//處理source0
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) {
//處理blocks
__CFRunLoopDoBlocks(rl, rlm);
}
//判斷有誤source1
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
//如果有source1,就跳轉(zhuǎn)到handle_msg
goto handle_msg;
}
//通知Observer即將休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
//等待別的消息來(lái)喚醒當(dāng)前線程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
__CFRunLoopUnsetSleeping(rl);
//通知Observer結(jié)束休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
handle_msg:;
if (被timer喚醒) {
//處理timers
__CFRunLoopDoTimers(rl, rlm, mach_absolute_time());
}
else if (被GCD喚醒) {
//處理gcd
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
} else {//被source1喚醒
//處理source1
__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply);
}
//處理blocks
__CFRunLoopDoBlocks(rl, rlm);
//設(shè)置返回值
if (sourceHandledThisLoop && stopAfterHandle) {
retVal = kCFRunLoopRunHandledSource;
} else if (timeout_context->termTSR < mach_absolute_time()) {
retVal = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) {
__CFRunLoopUnsetStopped(rl);
retVal = kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
retVal = kCFRunLoopRunStopped;
} else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
retVal = kCFRunLoopRunFinished;
}
voucher_mach_msg_revert(voucherState);
os_release(voucherCopy);
} while (0 == retVal);
return retVal;
}
5. 阻塞是切換到內(nèi)核態(tài),沒(méi)有消息就讓線程休眠,有消息就喚醒線程。
runloop實(shí)現(xiàn)原理:
用戶(hù)態(tài):處理消息。
內(nèi)核態(tài):沒(méi)有消息就讓線程休眠,有消息就喚醒線程。
6.runloop是怎么響應(yīng)用戶(hù)操作的,具體流程是什么樣的?source0->source1
source0去捕捉事件,source1處理事件。
7.平時(shí)都是怎么用runloop的?
(1)控制線程生命周期
線程保活OC實(shí)現(xiàn):
@interface ViewController ()
@property (strong, nonatomic) MJThread *thread;
@property (assign, nonatomic, getter=isStoped) BOOL stopped;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
self.stopped = NO;
self.thread = [[MJThread alloc] initWithBlock:^{
NSLog(@"%@----begin----", [NSThread currentThread]);
// 往RunLoop里面添加Source\Timer\Observer
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
while (weakSelf && !weakSelf.isStoped) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"%@----end----", [NSThread currentThread]);
}];
[self.thread start];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if (!self.thread) return;
[self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}
// 子線程需要執(zhí)行的任務(wù)
- (void)test
{
NSLog(@"%s %@", __func__, [NSThread currentThread]);
}
- (IBAction)stop {
if (!self.thread) return;
// 在子線程調(diào)用stop(waitUntilDone設(shè)置為YES,代表子線程的代碼執(zhí)行完畢后,這個(gè)方法才會(huì)往下走)
[self performSelector:@selector(stopThread) onThread:self.thread withObject:nil waitUntilDone:YES];
}
// 用于停止子線程的RunLoop
- (void)stopThread
{
// 設(shè)置標(biāo)記為YES
self.stopped = YES;
// 停止RunLoop
CFRunLoopStop(CFRunLoopGetCurrent());
NSLog(@"%s %@", __func__, [NSThread currentThread]);
// 清空線程
self.thread = nil;
}
- (void)dealloc
{
NSLog(@"%s", __func__);
[self stop];
}
@end
封裝使用
線程?;頒實(shí)現(xiàn):
封裝實(shí)現(xiàn)
上面2個(gè)封裝的使用前提條件:在某個(gè)固定子線程下串行執(zhí)行某個(gè)任務(wù),非并發(fā)的。
(2)解決NSTimer在滑動(dòng)時(shí)停止工作的問(wèn)題
使用手動(dòng)定時(shí)器把它加到commonmode下即可。
(3)監(jiān)控應(yīng)用卡頓
(4)性能優(yōu)化
Runloop
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 版本:ios 1.2.1 亮點(diǎn): 1.app角標(biāo)可以實(shí)時(shí)更新天氣溫度或選擇空氣質(zhì)量,建議處女座就不要選了,不然老想...
- 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂(lè)有人憂(yōu)愁,有人驚喜有人失落,有的覺(jué)得收獲滿(mǎn)滿(mǎn)有...
- 兔子雖然是枚小碩 但學(xué)校的碩士四人寢不夠 就被分到了博士樓里 兩人一間 在學(xué)校的最西邊 靠山 兔子的室友身體不好 ...