日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

iOS底层原理探究-Runloop

發(fā)布時(shí)間:2023/11/29 编程问答 64 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS底层原理探究-Runloop 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Runloop

1. 概述

一般來(lái)說(shuō),一個(gè)線程只能執(zhí)行一個(gè)任務(wù),執(zhí)行完就會(huì)退出,如果我們需要一種機(jī)制,讓線程能隨時(shí)處理時(shí)間但并不退出,那么 RunLoop 就是這樣的一個(gè)機(jī)制。Runloop是事件接收和分發(fā)機(jī)制的一個(gè)實(shí)現(xiàn)。

RunLoop實(shí)際上是一個(gè)對(duì)象,這個(gè)對(duì)象在循環(huán)中用來(lái)處理程序運(yùn)行過(guò)程中出現(xiàn)的各種事件(比如說(shuō)觸摸事件、UI刷新事件、定時(shí)器事件、Selector事件),從而保持程序的持續(xù)運(yùn)行;而且在沒(méi)有事件處理的時(shí)候,會(huì)進(jìn)入睡眠模式,從而節(jié)省CPU資源,提高程序性能。

簡(jiǎn)單的說(shuō)run loop是事件驅(qū)動(dòng)的一個(gè)大循環(huán),如下代碼所示:

int main(int argc, char * argv[]) {//程序一直運(yùn)行狀態(tài)while (AppIsRunning) {//睡眠狀態(tài),等待喚醒事件id whoWakesMe = SleepForWakingUp();//得到喚醒事件id event = GetEvent(whoWakesMe);//開(kāi)始處理事件HandleEvent(event);}return 0; } 復(fù)制代碼

2. Runloop 基本作用

2.1 保持程序持續(xù)運(yùn)行

程序一啟動(dòng)就會(huì)開(kāi)一個(gè)主線程,主線程一開(kāi)起來(lái)就會(huì)跑一個(gè)主線程對(duì)應(yīng)的Runloop, Runloop保證主線程不會(huì)被銷毀,也就保證了程序的持續(xù)運(yùn)行。不光iOS,在其他的編程平臺(tái),Android, Windows等都有一個(gè)類似Runloop的機(jī)制保證程序的持續(xù)運(yùn)行。

2.2 處理App中的各類事件

系統(tǒng)級(jí)別

GCD, mach kernel, block, pthread

應(yīng)用層

NSTimer, UIEvent, Autorelease, NSObject(NSDelayedPerforming), NSObject(NSThreadPerformAddition), CADisplayLink, CATransition, CAAnimation, dispatch_get_main_queue() (GCD 中dispatch到main queue的block會(huì)被dispatch到main Runloop中執(zhí)行), NSPort, NSURLConnection, AFNetworking(這個(gè)第三方網(wǎng)絡(luò)請(qǐng)求框架使用在開(kāi)啟新線程中添加自己到Runloop監(jiān)聽(tīng)事件)

2.3 節(jié)省CPU資源,提高程序性能

程序運(yùn)行起來(lái)時(shí),當(dāng)什么操作都沒(méi)有做的時(shí)候,Runloop告訴CPU, 現(xiàn)在沒(méi)有事情做,我要去休息, 這時(shí)CPU就會(huì)將資源釋放出來(lái)去做其他的事情,當(dāng)有事情做的時(shí)候Runloop就會(huì)立馬起來(lái)去做事情。

3. Runloop 的開(kāi)啟

程序入口

iOS 程序的入口是 main 函數(shù)

int main(int argc, char * argv[]) {@autoreleasepool {return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));} } 復(fù)制代碼

程序主線程一開(kāi)起來(lái),就會(huì)跑一個(gè)和主線程對(duì)應(yīng)的Runloop, 那么Runloop一定是在程序的入口main函數(shù)中開(kāi)啟。

在main thread 堆棧中所處的位置

堆棧最底層是start(dyld),往上依次是main,UIApplication(main.m) -> GSEventRunModal(Graphic Services) -> RunLoop(包含CFRunLoopRunSpecific,__CFRunLoopRun,__CFRunLoopDoSouces0,CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION) -> Handle Touch Event

4. Runloop 原理

CFRunLoop開(kāi)源代碼:http://opensource.apple.com/source/CF/CF-855.17/

Runloop 源碼:

void CFRunLoopRun(void) { /* DOES CALLOUT */int32_t result;do {result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);CHECK_FOR_FORK();} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result); } 復(fù)制代碼

我們發(fā)現(xiàn)RunLoop確實(shí)是do while通過(guò)判斷result的值實(shí)現(xiàn)的。因此,我們可以把RunLoop看成一個(gè)死循環(huán)。如果沒(méi)有RunLoop,UIApplicationMain函數(shù)執(zhí)行完畢之后將直接返回,也就沒(méi)有程序持續(xù)運(yùn)行一說(shuō)了。

執(zhí)行順序的偽代碼:

int32_t __CFRunLoopRun() {// 通知即將進(jìn)入runloop__CFRunLoopDoObservers(KCFRunLoopEntry);do{// 通知將要處理timer和source__CFRunLoopDoObservers(kCFRunLoopBeforeTimers);__CFRunLoopDoObservers(kCFRunLoopBeforeSources);// 處理非延遲的主線程調(diào)用__CFRunLoopDoBlocks();// 處理Source0事件__CFRunLoopDoSource0();if (sourceHandledThisLoop) {__CFRunLoopDoBlocks();}/// 如果有 Source1 (基于port) 處于 ready 狀態(tài),直接處理這個(gè) Source1 然后跳轉(zhuǎn)去處理消息。if (__Source0DidDispatchPortLastTime) {Boolean hasMsg = __CFRunLoopServiceMachPort();if (hasMsg) goto handle_msg;}/// 通知 Observers: RunLoop 的線程即將進(jìn)入休眠(sleep)。if (!sourceHandledThisLoop) {__CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeWaiting);}// GCD dispatch main queueCheckIfExistMessagesInMainDispatchQueue();// 即將進(jìn)入休眠_(dá)_CFRunLoopDoObservers(kCFRunLoopBeforeWaiting);// 等待內(nèi)核mach_msg事件mach_port_t wakeUpPort = SleepAndWaitForWakingUpPorts();// 等待。。。// 從等待中醒來(lái)__CFRunLoopDoObservers(kCFRunLoopAfterWaiting);// 處理因timer的喚醒if (wakeUpPort == timerPort)__CFRunLoopDoTimers();// 處理異步方法喚醒,如dispatch_asyncelse if (wakeUpPort == mainDispatchQueuePort)__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()// 處理Source1else__CFRunLoopDoSource1();// 再次確保是否有同步的方法需要調(diào)用__CFRunLoopDoBlocks();} while (!stop && !timeout);// 通知即將退出runloop__CFRunLoopDoObservers(CFRunLoopExit); } 復(fù)制代碼

5. Runloop 對(duì)象

RunLoop對(duì)象包括Fundation中的NSRunLoop對(duì)象和CoreFoundation中的CFRunLoopRef對(duì)象。因?yàn)镕undation框架是基于CFRunLoopRef的封裝,因此我們學(xué)習(xí)RunLoop還是要研究CFRunLoopRef 源碼。

獲得Runloop 對(duì)象

//Foundation [NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對(duì)象 [NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對(duì)象//Core Foundation CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對(duì)象 CFRunLoopGetMain(); // 獲得主線程的RunLoop對(duì)象 復(fù)制代碼

值的注意的是子線程中的runloop不是默認(rèn)開(kāi)啟的,需要手動(dòng)開(kāi)啟,當(dāng)調(diào)用 [NSRunLoop currentRunLoop] 時(shí),若已存在當(dāng)前線程的runloop返回,若不存在創(chuàng)建一個(gè)新的runloop對(duì)象再返回。

6. Runloop 和 線程

6.1 Runloop 和 線程 之間的關(guān)系

  • 每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的Runloop 對(duì)象
  • 主線程的Runloop已經(jīng)自動(dòng)創(chuàng)建好了,子線程的Runloop需要手動(dòng)創(chuàng)建
  • Runloop在第一次獲取時(shí)創(chuàng)建,在線程結(jié)束時(shí)銷毀
  • Thread 包含一個(gè)CFRunloop, 一個(gè)CFRunloop 包含一種CFRunloopMode, model 包含 CFRunloopSource, CFRunloopTimer, CFRunloopObserver.
  • 6.2 主線程想關(guān)聯(lián)的Runloop創(chuàng)建

    CFRunloopRef 源碼

    // 創(chuàng)建字典CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);// 創(chuàng)建主線程 根據(jù)傳入的主線程創(chuàng)建主線程對(duì)應(yīng)的RunLoopCFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());// 保存主線程 將主線程-key和RunLoop-Value保存到字典中CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop); 復(fù)制代碼

    6.3 創(chuàng)建與子線程想關(guān)聯(lián)的Runloop

    Apple 不允許直接創(chuàng)建Runloop, 它只提供了兩個(gè)自動(dòng)獲取的函數(shù): CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。 CFRunLoopRef源碼:

    /// 用DefaultMode啟動(dòng) void CFRunLoopRun(void) {CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false); }/// 用指定的Mode啟動(dòng),允許設(shè)置RunLoop超時(shí)時(shí)間 int CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean stopAfterHandle) {return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled); }/// RunLoop的實(shí)現(xiàn) int CFRunLoopRunSpecific(runloop, modeName, seconds, stopAfterHandle) {/// 首先根據(jù)modeName找到對(duì)應(yīng)modeCFRunLoopModeRef currentMode = __CFRunLoopFindMode(runloop, modeName, false);/// 如果mode里沒(méi)有source/timer/observer, 直接返回。if (__CFRunLoopModeIsEmpty(currentMode)) return;/// 1. 通知 Observers: RunLoop 即將進(jìn)入 loop。__CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopEntry);/// 內(nèi)部函數(shù),進(jìn)入loop__CFRunLoopRun(runloop, currentMode, seconds, returnAfterSourceHandled) {Boolean sourceHandledThisLoop = NO;int retVal = 0;do {/// 2. 通知 Observers: RunLoop 即將觸發(fā) Timer 回調(diào)。__CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeTimers);/// 3. 通知 Observers: RunLoop 即將觸發(fā) Source0 (非port) 回調(diào)。__CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeSources);/// 執(zhí)行被加入的block__CFRunLoopDoBlocks(runloop, currentMode);/// 4. RunLoop 觸發(fā) Source0 (非port) 回調(diào)。sourceHandledThisLoop = __CFRunLoopDoSources0(runloop, currentMode, stopAfterHandle);/// 執(zhí)行被加入的block__CFRunLoopDoBlocks(runloop, currentMode);/// 5. 如果有 Source1 (基于port) 處于 ready 狀態(tài),直接處理這個(gè) Source1 然后跳轉(zhuǎn)去處理消息。if (__Source0DidDispatchPortLastTime) {Boolean hasMsg = __CFRunLoopServiceMachPort(dispatchPort, &msg)if (hasMsg) goto handle_msg;}/// 通知 Observers: RunLoop 的線程即將進(jìn)入休眠(sleep)。if (!sourceHandledThisLoop) {__CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeWaiting);}/// 7. 調(diào)用 mach_msg 等待接受 mach_port 的消息。線程將進(jìn)入休眠, 直到被下面某一個(gè)事件喚醒。/// ? 一個(gè)基于 port 的Source 的事件。/// ? 一個(gè) Timer 到時(shí)間了/// ? RunLoop 自身的超時(shí)時(shí)間到了/// ? 被其他什么調(diào)用者手動(dòng)喚醒__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort) {mach_msg(msg, MACH_RCV_MSG, port); // thread wait for receive msg}/// 8. 通知 Observers: RunLoop 的線程剛剛被喚醒了。__CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopAfterWaiting);/// 收到消息,處理消息。handle_msg:/// 9.1 如果一個(gè) Timer 到時(shí)間了,觸發(fā)這個(gè)Timer的回調(diào)。if (msg_is_timer) {__CFRunLoopDoTimers(runloop, currentMode, mach_absolute_time())} /// 9.2 如果有dispatch到main_queue的block,執(zhí)行block。else if (msg_is_dispatch) {__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);} /// 9.3 如果一個(gè) Source1 (基于port) 發(fā)出事件了,處理這個(gè)事件else {CFRunLoopSourceRef source1 = __CFRunLoopModeFindSourceForMachPort(runloop, currentMode, livePort);sourceHandledThisLoop = __CFRunLoopDoSource1(runloop, currentMode, source1, msg);if (sourceHandledThisLoop) {mach_msg(reply, MACH_SEND_MSG, reply);}}/// 執(zhí)行加入到Loop的block__CFRunLoopDoBlocks(runloop, currentMode);if (sourceHandledThisLoop && stopAfterHandle) {/// 進(jìn)入loop時(shí)參數(shù)說(shuō)處理完事件就返回。retVal = kCFRunLoopRunHandledSource;} else if (timeout) {/// 超出傳入?yún)?shù)標(biāo)記的超時(shí)時(shí)間了retVal = kCFRunLoopRunTimedOut;} else if (__CFRunLoopIsStopped(runloop)) {/// 被外部調(diào)用者強(qiáng)制停止了retVal = kCFRunLoopRunStopped;} else if (__CFRunLoopModeIsEmpty(runloop, currentMode)) {/// source/timer/observer一個(gè)都沒(méi)有了retVal = kCFRunLoopRunFinished;}/// 如果沒(méi)超時(shí),mode里沒(méi)空,loop也沒(méi)被停止,那繼續(xù)loop。} while (retVal == 0);}/// 10. 通知 Observers: RunLoop 即將退出。__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); } 復(fù)制代碼

    可以看出,線程和 RunLoop 之間是一一對(duì)應(yīng)的,其關(guān)系是保存在一個(gè)全局的 Dictionary 里。線程剛創(chuàng)建時(shí)并沒(méi)有 RunLoop,如果你不主動(dòng)獲取,那它一直都不會(huì)有。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時(shí),RunLoop 的銷毀是發(fā)生在線程結(jié)束時(shí)。你只能在一個(gè)線程的內(nèi)部獲取其 RunLoop(主線程除外)。

    [NSRunLoop currentRunLoop];方法調(diào)用時(shí),會(huì)先看一下字典里有沒(méi)有存子線程相對(duì)用的RunLoop,如果有則直接返回RunLoop,如果沒(méi)有則會(huì)創(chuàng)建一個(gè),并將與之對(duì)應(yīng)的子線程存入字典中。

    7. Runloop 相關(guān)類

    Core Foundation中關(guān)于RunLoop的5個(gè)類:

    CFRunLoopRef //獲得當(dāng)前RunLoop和主RunLoop CFRunLoopModeRef //運(yùn)行模式,只能選擇一種,在不同模式中做不同的操作 CFRunLoopSourceRef //事件源,輸入源 CFRunLoopTimerRef //定時(shí)器時(shí)間 CFRunLoopObserverRef //觀察者 復(fù)制代碼

    7.1 CFRunLoopModeRef

    一個(gè)Runloop包含若干個(gè)Mode, 每個(gè)Mode又包含若干個(gè)Source / Timer / Observer. 每次調(diào)用Runloop 的主函數(shù)時(shí),只能指定其中一個(gè)Mode, 這個(gè)Mode被稱作 CurrentMode. 如果需要切換Mode, 只能退出Loop, 再重新指定一個(gè)Mode進(jìn)入。這樣做主要是為了分隔開(kāi)不同組的 Source/Timer/Observer, 讓其互不影響。

    系統(tǒng)默認(rèn)注冊(cè)了 5 個(gè)Mode, 其中常見(jiàn)的有第 1,2 種:

    1. kCFRunLoopDefaultMode:App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行 2. UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他 Mode 影響 3. UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode,啟動(dòng)完成后就不再使用 4. GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到 5. kCFRunLoopCommonModes: 這是一個(gè)占位用的Mode,作為標(biāo)記kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一種真正的Mode 復(fù)制代碼

    上面的Source/Timer/Observer 被統(tǒng)稱為 model item, 一個(gè)item 可以被同時(shí)加入多個(gè) Mode. 但一個(gè)item被重復(fù)加入同一個(gè)mode時(shí)是不會(huì)有效果的。如果一個(gè)mode中一個(gè)item都沒(méi)有,則Runloop會(huì)直接退出,不進(jìn)入循環(huán)。

    Mode 間切換 我們平時(shí)在開(kāi)發(fā)中一定遇到過(guò),當(dāng)我們使用NSTimer每一段時(shí)間執(zhí)行一些事情時(shí)滑動(dòng)UIScrollView,NSTimer就會(huì)暫停,當(dāng)我們停止滑動(dòng)以后,NSTimer又會(huì)重新恢復(fù)的情況,我們通過(guò)一段代碼來(lái)看一下:

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {// [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];// 加入到RunLoop中才可以運(yùn)行// 1. 把定時(shí)器添加到RunLoop中,并且選擇默認(rèn)運(yùn)行模式NSDefaultRunLoopMode = kCFRunLoopDefaultMode// [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];// 當(dāng)textFiled滑動(dòng)的時(shí)候,timer失效,停止滑動(dòng)時(shí),timer恢復(fù)// 原因:當(dāng)textFiled滑動(dòng)的時(shí)候,RunLoop的Mode會(huì)自動(dòng)切換成UITrackingRunLoopMode模式,因此timer失效,當(dāng)停止滑動(dòng),RunLoop又會(huì)切換回NSDefaultRunLoopMode模式,因此timer又會(huì)重新啟動(dòng)了// 2. 當(dāng)我們將timer添加到UITrackingRunLoopMode模式中,此時(shí)只有我們?cè)诨瑒?dòng)textField時(shí)timer才會(huì)運(yùn)行// [[NSRunLoop mainRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];// 3. 那個(gè)如何讓timer在兩個(gè)模式下都可以運(yùn)行呢?// 3.1 在兩個(gè)模式下都添加timer 是可以的,但是timer添加了兩次,并不是同一個(gè)timer// 3.2 使用站位的運(yùn)行模式 NSRunLoopCommonModes標(biāo)記,凡是被打上NSRunLoopCommonModes標(biāo)記的都可以運(yùn)行,下面兩種模式被打上標(biāo)簽//0 : <CFString 0x10b7fe210 [0x10a8c7a40]>{contents = "UITrackingRunLoopMode"}//2 : <CFString 0x10a8e85e0 [0x10a8c7a40]>{contents = "kCFRunLoopDefaultMode"}// 因此也就是說(shuō)如果我們使用NSRunLoopCommonModes,timer可以在UITrackingRunLoopMode,kCFRunLoopDefaultMode兩種模式下運(yùn)行[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];NSLog(@"%@",[NSRunLoop mainRunLoop]); } -(void)show {NSLog(@"-------"); } 復(fù)制代碼

    由上述代碼可以看出,NSTimer不管用是因?yàn)镸ode的切換,因?yàn)槿绻覀冊(cè)谥骶€程使用定時(shí)器,此時(shí)RunLoop的Mode為kCFRunLoopDefaultMode,即定時(shí)器屬于kCFRunLoopDefaultMode,那么此時(shí)我們滑動(dòng)ScrollView時(shí),RunLoop的Mode會(huì)切換到UITrackingRunLoopMode,因此在主線程的定時(shí)器就不在管用了,調(diào)用的方法也就不再執(zhí)行了,當(dāng)我們停止滑動(dòng)時(shí),RunLoop的Mode切換回kCFRunLoopDefaultMode,所有NSTimer就又管用了。

    使用GCD也可以創(chuàng)建計(jì)時(shí)器,而且更為精確:

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//創(chuàng)建隊(duì)列dispatch_queue_t queue = dispatch_get_global_queue(0, 0);//1.創(chuàng)建一個(gè)GCD定時(shí)器/*第一個(gè)參數(shù):表明創(chuàng)建的是一個(gè)定時(shí)器第四個(gè)參數(shù):隊(duì)列*/dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);// 需要對(duì)timer進(jìn)行強(qiáng)引用,保證其不會(huì)被釋放掉,才會(huì)按時(shí)調(diào)用block塊// 局部變量,讓指針強(qiáng)引用self.timer = timer;//2.設(shè)置定時(shí)器的開(kāi)始時(shí)間,間隔時(shí)間,精準(zhǔn)度/*第1個(gè)參數(shù):要給哪個(gè)定時(shí)器設(shè)置第2個(gè)參數(shù):開(kāi)始時(shí)間第3個(gè)參數(shù):間隔時(shí)間第4個(gè)參數(shù):精準(zhǔn)度 一般為0 在允許范圍內(nèi)增加誤差可提高程序的性能GCD的單位是納秒 所以要*NSEC_PER_SEC*/dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);//3.設(shè)置定時(shí)器要執(zhí)行的事情dispatch_source_set_event_handler(timer, ^{NSLog(@"---%@--",[NSThread currentThread]);});// 啟動(dòng)dispatch_resume(timer); } 復(fù)制代碼

    7.2 CFRunLoopSourceRef

    Source分為兩種:

    Source0:非基于Port的 用于用戶主動(dòng)觸發(fā)的事件(點(diǎn)擊button 或點(diǎn)擊屏幕) Source1:基于Port的 通過(guò)內(nèi)核和其他線程相互發(fā)送消息(與內(nèi)核相關(guān)) 注意:Source1在處理的時(shí)候會(huì)分發(fā)一些操作給Source0去處理

    7.3 CFRunLoopTimer

    NSTimer是對(duì)RunLoopTimer的封裝

    + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;+ (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel; - (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode;復(fù)制代碼

    7.4 CFRunLoopObserverRef

    CFRunLoopObserverRef是觀察者,能夠監(jiān)聽(tīng)RunLoop的狀態(tài)改變。 我們直接來(lái)看代碼,給RunLoop添加監(jiān)聽(tīng)者,監(jiān)聽(tīng)其運(yùn)行狀態(tài):

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//創(chuàng)建監(jiān)聽(tīng)者/*第一個(gè)參數(shù) CFAllocatorRef allocator:分配存儲(chǔ)空間 CFAllocatorGetDefault()默認(rèn)分配第二個(gè)參數(shù) CFOptionFlags activities:要監(jiān)聽(tīng)的狀態(tài) kCFRunLoopAllActivities 監(jiān)聽(tīng)所有狀態(tài)第三個(gè)參數(shù) Boolean repeats:YES:持續(xù)監(jiān)聽(tīng) NO:不持續(xù)第四個(gè)參數(shù) CFIndex order:優(yōu)先級(jí),一般填0即可第五個(gè)參數(shù) :回調(diào) 兩個(gè)參數(shù)observer:監(jiān)聽(tīng)者 activity:監(jiān)聽(tīng)的事件*//*所有事件typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {kCFRunLoopEntry = (1UL << 0), // 即將進(jìn)入RunLoopkCFRunLoopBeforeTimers = (1UL << 1), // 即將處理TimerkCFRunLoopBeforeSources = (1UL << 2), // 即將處理SourcekCFRunLoopBeforeWaiting = (1UL << 5), //即將進(jìn)入休眠kCFRunLoopAfterWaiting = (1UL << 6),// 剛從休眠中喚醒kCFRunLoopExit = (1UL << 7),// 即將退出RunLoopkCFRunLoopAllActivities = 0x0FFFFFFFU};*/CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch (activity) {case kCFRunLoopEntry:NSLog(@"RunLoop進(jìn)入");break;case kCFRunLoopBeforeTimers:NSLog(@"RunLoop要處理Timers了");break;case kCFRunLoopBeforeSources:NSLog(@"RunLoop要處理Sources了");break;case kCFRunLoopBeforeWaiting:NSLog(@"RunLoop要休息了");break;case kCFRunLoopAfterWaiting:NSLog(@"RunLoop醒來(lái)了");break;case kCFRunLoopExit:NSLog(@"RunLoop退出了");break;default:break;}});// 給RunLoop添加監(jiān)聽(tīng)者/*第一個(gè)參數(shù) CFRunLoopRef rl:要監(jiān)聽(tīng)哪個(gè)RunLoop,這里監(jiān)聽(tīng)的是主線程的RunLoop第二個(gè)參數(shù) CFRunLoopObserverRef observer 監(jiān)聽(tīng)者第三個(gè)參數(shù) CFStringRef mode 要監(jiān)聽(tīng)RunLoop在哪種運(yùn)行模式下的狀態(tài)*/CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);/*CF的內(nèi)存管理(Core Foundation)凡是帶有Create、Copy、Retain等字眼的函數(shù),創(chuàng)建出來(lái)的對(duì)象,都需要在最后做一次releaseGCD本來(lái)在iOS6.0之前也是需要我們釋放的,6.0之后GCD已經(jīng)納入到了ARC中,所以我們不需要管了*/CFRelease(observer); } 復(fù)制代碼

    運(yùn)行結(jié)果:

    8. Runloop 退出

  • 主線程銷魂Runloop退出
  • Mode中有一些Timer, Source, Observer, 這些保證Mode不為空時(shí)保證Runloop沒(méi)有空轉(zhuǎn)并且是在運(yùn)行的,當(dāng)Mode中為空的時(shí)候,Runloop會(huì)立刻退出。
  • 我們?cè)趩?dòng)Runloop的時(shí)候可以設(shè)置什么時(shí)候停止。
  • [NSRunLoop currentRunLoop]runUntilDate:<#(nonnull NSDate *)#> [NSRunLoop currentRunLoop]runMode:<#(nonnull NSString *)#> beforeDate:<#(nonnull NSDate *)#> 復(fù)制代碼

    9. 一些有關(guān)Runloop的問(wèn)題

    9.1 基于NSTimer的輪播器什么情況下會(huì)被頁(yè)面滾動(dòng)暫停,怎樣可以不被暫停,為什么?

    NSTimer不管用是因?yàn)镸ode的切換,因?yàn)槿绻覀冊(cè)谥骶€程使用定時(shí)器,此時(shí)RunLoop的Mode為kCFRunLoopDefaultMode,即定時(shí)器屬于kCFRunLoopDefaultMode,那么此時(shí)我們滑動(dòng)ScrollView時(shí),RunLoop的Mode會(huì)切換到UITrackingRunLoopMode,因此在主線程的定時(shí)器就不在管用了,調(diào)用的方法也就不再執(zhí)行了,當(dāng)我們停止滑動(dòng)時(shí),RunLoop的Mode切換回kCFRunLoopDefaultMode,所有NSTimer就又管用了。若想定時(shí)器繼續(xù)執(zhí)行,需要將NSTimer 注冊(cè)為 kCFRunLoopCommonModes 。

    9.2 延遲執(zhí)行performSelecter相關(guān)方法是怎樣被執(zhí)行的?在子線程中也是一樣的嗎?

    當(dāng)調(diào)用 NSObject 的 performSelecter:afterDelay: 后,實(shí)際上其內(nèi)部會(huì)創(chuàng)建一個(gè) Timer 并添加到當(dāng)前線程的 RunLoop 中。所以如果當(dāng)前線程沒(méi)有 RunLoop,則這個(gè)方法會(huì)失效。 當(dāng)調(diào)用 performSelector:onThread: 時(shí),實(shí)際上其會(huì)創(chuàng)建一個(gè) Timer 加到對(duì)應(yīng)的線程去,同樣的,如果對(duì)應(yīng)線程沒(méi)有 RunLoop 該方法也會(huì)失效。

    9.3 事件響應(yīng)和手勢(shì)識(shí)別底層處理是一致的嗎,為什么?

    事件響應(yīng): 蘋果注冊(cè)了一個(gè) Source1 (基于 mach port 的) 用來(lái)接收系統(tǒng)事件,其回調(diào)函數(shù)為 __IOHIDEventSystemClientQueueCallback()。 當(dāng)一個(gè)硬件事件(觸摸/鎖屏/搖晃等)發(fā)生后,首先由 IOKit.framework 生成一個(gè) IOHIDEvent 事件并由 SpringBoard 接收。SpringBoard 只接收按鍵(鎖屏/靜音等),觸摸,加速,接近傳感器等幾種 Event,隨后用 mach port 轉(zhuǎn)發(fā)給需要的App進(jìn)程。隨后蘋果注冊(cè)的那個(gè) Source1 就會(huì)觸發(fā)回調(diào),并調(diào)用 _UIApplicationHandleEventQueue() 進(jìn)行應(yīng)用內(nèi)部的分發(fā)。 _UIApplicationHandleEventQueue() 會(huì)把 IOHIDEvent 處理并包裝成 UIEvent 進(jìn)行處理或分發(fā),其中包括識(shí)別 UIGesture/處理屏幕旋轉(zhuǎn)/發(fā)送給 UIWindow 等。通常事件比如 UIButton 點(diǎn)擊、touchesBegin/Move/End/Cancel 事件都是在這個(gè)回調(diào)中完成的。

    手勢(shì)識(shí)別: 當(dāng)上面的 _UIApplicationHandleEventQueue() 識(shí)別了一個(gè)手勢(shì)時(shí),其首先會(huì)調(diào)用 Cancel 將當(dāng)前的 touchesBegin/Move/End 系列回調(diào)打斷。隨后系統(tǒng)將對(duì)應(yīng)的 UIGestureRecognizer 標(biāo)記為待處理。 蘋果注冊(cè)了一個(gè) Observer 監(jiān)測(cè) BeforeWaiting (Loop即將進(jìn)入休眠) 事件,這個(gè)Observer的回調(diào)函數(shù)是 _UIGestureRecognizerUpdateObserver(),其內(nèi)部會(huì)獲取所有剛被標(biāo)記為待處理的 GestureRecognizer,并執(zhí)行GestureRecognizer的回調(diào)。 當(dāng)有 UIGestureRecognizer 的變化(創(chuàng)建/銷毀/狀態(tài)改變)時(shí),這個(gè)回調(diào)都會(huì)進(jìn)行相應(yīng)處理。

    9.4 界面刷新時(shí),是在什么時(shí)候會(huì)真正執(zhí)行刷新,為什么會(huì)刷新不及時(shí)?

    當(dāng)在操作 UI 時(shí),比如改變了 Frame、更新了 UIView/CALayer 的層次時(shí),或者手動(dòng)調(diào)用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,這個(gè) UIView/CALayer 就被標(biāo)記為待處理,并被提交到一個(gè)全局的容器去。

    蘋果注冊(cè)了一個(gè) Observer 監(jiān)聽(tīng) BeforeWaiting(即將進(jìn)入休眠) 和 Exit (即將退出Loop) 事件,回調(diào)去執(zhí)行一個(gè)很長(zhǎng)的函數(shù):_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。這個(gè)函數(shù)里會(huì)遍歷所有待處理的 UIView/CAlayer 以執(zhí)行實(shí)際的繪制和調(diào)整,并更新 UI 界面。所以說(shuō)界面刷新并不一定是在setNeedsLayout相關(guān)的代碼執(zhí)行后立刻進(jìn)行的。

    9.5 項(xiàng)目程序運(yùn)行中,總是伴隨著多次自動(dòng)釋放池的創(chuàng)建和銷毀,這些是在什么時(shí)候發(fā)生的呢?

    系統(tǒng)就是通過(guò)@autoreleasepool {}這種方式來(lái)為我們創(chuàng)建自動(dòng)釋放池的,一個(gè)線程對(duì)應(yīng)一個(gè)runloop,系統(tǒng)會(huì)為每一個(gè)runloop隱式的創(chuàng)建一個(gè)自動(dòng)釋放池,所有的autoreleasePool構(gòu)成一個(gè)棧式結(jié)構(gòu),在每個(gè)runloop結(jié)束時(shí),當(dāng)前棧頂?shù)腶utoreleasePool會(huì)被銷毀,而且會(huì)對(duì)其中的每一個(gè)對(duì)象做一次release(嚴(yán)格來(lái)說(shuō),是你對(duì)這個(gè)對(duì)象做了幾次autorelease就會(huì)做幾次release,不一定是一次),特別指出,使用容器的block版本的枚舉器的時(shí)候,系統(tǒng)會(huì)自動(dòng)添加一個(gè)autoreleasePool

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { // 這里被一個(gè)局部@autoreleasepool包圍著 }]; 復(fù)制代碼

    9.6 當(dāng)我們?cè)谧泳€程上需要執(zhí)行代理方法或者回調(diào)時(shí),怎么確保當(dāng)前線程沒(méi)有被銷毀?

    首先引入一個(gè)概念:Event_loop,一般一個(gè)線程執(zhí)行完任務(wù)后就會(huì)退出,當(dāng)需要保證該線程不退出,可以通過(guò)類似以下方式:

    function do_loop() {initialize();do {var message = get_next_message();process_message(message);} while (message != quit); } 復(fù)制代碼

    開(kāi)啟一個(gè)循環(huán),保證線程不退出,這就是Event_loop模型。這是在很多操作系統(tǒng)中都使用的模型,例如OS/iOS中的RunLoop。這種模型最大的作用就是管理事件/消息,在有新消息到來(lái)時(shí)立刻喚醒處理,沒(méi)有待處理消息時(shí)線程休眠,避免資源浪費(fèi)。

    10 Runloop 使用

    10.1 AFNetworking

    使用NSOperation+NSURLConnection并發(fā)模型都會(huì)面臨NSURLConnection下載完成前線程退出導(dǎo)致NSOperation對(duì)象接收不到回調(diào)的問(wèn)題。AFNetWorking解決這個(gè)問(wèn)題的方法是按照官方的guid NSURLConnection 上寫(xiě)的NSURLConnection的delegate方法需要在connection發(fā)起的線程runloop中調(diào)用,于是AFNetWorking直接借鑒了Apple自己的一個(gè)Demo的實(shí)現(xiàn)方法單獨(dú)起一個(gè)global thread,內(nèi)置一個(gè)runloop,所有的connection都由這個(gè)runloop發(fā)起,回調(diào)也是它接收,不占用主線程,也不耗CPU資源。

    + (void)networkRequestThreadEntryPoint:(id)__unused object {@autoreleasepool {[[NSThread currentThread] setName:@"AFNetworking"];NSRunLoop *runLoop = [NSRunLoop currentRunLoop];[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];[runLoop run];} }+ (NSThread *)networkRequestThread {static NSThread *_networkRequestThread = nil;static dispatch_once_t oncePredicate;dispatch_once(&oncePredicate, ^{_networkRequestThread =[[NSThread alloc] initWithTarget:selfselector:@selector(networkRequestThreadEntryPoint:)object:nil];[_networkRequestThread start];});return _networkRequestThread; } 復(fù)制代碼

    類似的可以用這個(gè)方法創(chuàng)建一個(gè)常駐服務(wù)的線程。

    10.2 TableView中實(shí)現(xiàn)平滑滾動(dòng)延遲加載圖片

    利用CFRunLoopMode的特性,可以將圖片的加載放到NSDefaultRunLoopMode的mode里,這樣在滾動(dòng)UITrackingRunLoopMode這個(gè)mode時(shí)不會(huì)被加載而影響到。

    UIImage *downloadedImage = ...; [self.imageView performSelector:@selector(setImage:)withObject:downloadedImageafterDelay:0inModes:@[NSDefaultRunLoopMode]]; 復(fù)制代碼

    10.3 接到程序崩潰時(shí)的信號(hào)進(jìn)行自主處理例如彈出提示等

    CFRunLoopRef runLoop = CFRunLoopGetCurrent(); NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop)); while (1) {for (NSString *mode in allModes) {CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);} } 復(fù)制代碼

    10.4 異步測(cè)試

    - (BOOL)runUntilBlock:(BOOL(^)())block timeout:(NSTimeInterval)timeout {__block Boolean fulfilled = NO;void (^beforeWaiting) (CFRunLoopObserverRef observer, CFRunLoopActivity activity) =^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {fulfilled = block();if (fulfilled) {CFRunLoopStop(CFRunLoopGetCurrent());}};CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, beforeWaiting);CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);// Run!CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, false);CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);CFRelease(observer);return fulfilled; } 復(fù)制代碼

    總結(jié)

    以上是生活随笔為你收集整理的iOS底层原理探究-Runloop的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    国内丰满少妇猛烈精品播 | 日韩在线一二三区 | 日韩精品一区电影 | 国产一级免费观看视频 | 国产精品自在线拍国产 | 在线观看涩涩 | 伊人久久在线观看 | 天天干天天拍天天操 | 免费日韩一区二区 | 色综合天天色综合 | 国产在线 一区二区三区 | 国产无区一区二区三麻豆 | 香蕉蜜桃视频 | 日韩中文在线字幕 | 日韩av一区二区在线 | 99视频播放| 狠狠色婷婷丁香六月 | 成人欧美亚洲 | 99精品视频免费观看 | 四虎永久精品在线 | 全久久久久久久久久久电影 | 色婷婷综合视频在线观看 | 国产一二三四在线视频 | 五月婷婷丁香激情 | 国产999| 九九久久久久久久久激情 | 久久精品一二三区 | 亚洲尺码电影av久久 | 国产伦理久久精品久久久久_ | 欧美成人黄色 | 精品产品国产在线不卡 | 亚洲乱码久久 | 精品视频久久久 | 三级av在线免费观看 | 国产精品少妇 | 国产精品欧美激情在线观看 | 久久精品免费播放 | 最新国产精品拍自在线播放 | 久久久久久久免费观看 | 狠狠色狠狠色合久久伊人 | 96av在线| 五月天高清欧美mv | 在线免费视频 你懂得 | 狠狠色丁香久久婷婷综合丁香 | 久久久久久久久艹 | 亚洲成人xxx | 国产精品99精品久久免费 | 亚洲国产中文字幕 | 欧美精品二 | 中文字幕一区二区在线观看 | 国产九九在线 | 天天躁日日躁狠狠躁av麻豆 | 色999视频 | 丁香花在线观看免费完整版视频 | 午夜天天操| 激情久久一区二区三区 | 欧美另类v | av在线收看 | 西西大胆免费视频 | 中文字幕一区二区三区四区在线视频 | 韩日视频在线 | 人人看人人做人人澡 | 国内精品国产三级国产aⅴ久 | 美女网站视频久久 | 国产精品一区二区免费看 | 亚洲国产精品久久久 | 粉嫩av一区二区三区四区五区 | 久久久久在线视频 | 一级a性色生活片久久毛片波多野 | 91tv国产成人福利 | 在线视频观看亚洲 | 免费看片成年人 | 99久久这里有精品 | 黄污网 | 久久视频在线观看中文字幕 | 亚洲精品在线观看视频 | 日韩一区二区三免费高清在线观看 | 久久久网页 | 免费精品人在线二线三线 | 精品视频在线免费观看 | 18国产精品白浆在线观看免费 | 一本一本久久a久久精品牛牛影视 | 国产97在线视频 | 国产手机在线视频 | av日韩国产 | 国产精品专区h在线观看 | av在线网站观看 | 国产美女精彩久久 | 国产无区一区二区三麻豆 | 国产韩国精品一区二区三区 | 国产69精品久久久久99尤 | 国产精品毛片久久久久久 | 91.精品高清在线观看 | 国产日韩在线播放 | 精品国自产在线观看 | 精品福利国产 | 久久精品国产免费 | 中文字幕亚洲精品在线观看 | 在线观看一区视频 | 国产精品久久久久久久久久白浆 | 亚洲午夜激情网 | 日韩成人不卡 | 欧美日韩高清不卡 | 欧美激情亚洲综合 | 国产一区av在线 | 国产一级视频在线观看 | 丝袜美腿在线 | 亚洲综合涩 | 九九涩涩av台湾日本热热 | 亚洲国产精品激情在线观看 | 一区二区三区四区在线免费观看 | 亚洲国产精品激情在线观看 | 五月天天色 | 国产成人精品一区二区三区福利 | 中文字幕一区二区三区四区视频 | 成人影视免费看 | 久草在线播放视频 | 欧美激情视频在线免费观看 | 韩国av免费在线观看 | 成人av在线亚洲 | 色欧美视频| 色婷婷视频在线 | 中文字幕中文中文字幕 | 国产一区二区不卡视频 | 一级性视频 | 最近中文字幕久久 | 免费福利在线 | 欧美网址在线观看 | 亚洲成人黄色av | 97av在线| 久久好看免费视频 | 日韩色综合 | 亚洲精品乱码久久久久久蜜桃动漫 | 午夜免费久久看 | 91精品国产九九九久久久亚洲 | 国产香蕉久久精品综合网 | 黄色一级动作片 | 欧美久久久久久久久中文字幕 | 欧美一区二区三区四区夜夜大片 | 麻豆视频免费观看 | 超碰在线亚洲 | 激情电影影院 | 色在线最新| 精品久久国产一区 | 亚洲精品免费观看 | 91黄色小视频 | 9i看片成人免费看片 | 在线观看亚洲精品视频 | 国内精品久久久久久久久 | 精品国产一区二区久久 | 久草免费在线观看视频 | 婷婷丁香导航 | 五月花婷婷 | 狠狠色丁香婷婷综合基地 | 免费国产在线观看 | 日本久久成人中文字幕电影 | 久草在线播放视频 | 国产成人精品一区二 | 91丨九色丨国产丨porny精品 | av大片免费在线观看 | 国产区在线视频 | 丁香婷婷激情 | 久久精品电影 | 国语自产偷拍精品视频偷 | 91在线www| 久久综合中文字幕 | 狠狠狠综合 | 91麻豆国产福利在线观看 | 久久免费毛片视频 | 日本视频高清 | 欧洲黄色片| 5月丁香婷婷综合 | 免费视频黄色 | 日韩欧美电影在线 | 中文字幕丝袜美腿 | 日韩在线观看第一页 | 91污视频在线 | 国产精品乱码久久久久 | 青草视频网 | 9在线观看免费高清完整 | 精品久久久久久一区二区里番 | 欧美日韩一区二区三区在线免费观看 | 天天操天天玩 | 91色九色| 精品v亚洲v欧美v高清v | 最新av在线播放 | 99久久精品免费看国产麻豆 | 亚洲视频综合 | 91麻豆国产| 中文字幕中文字幕在线一区 | 国产精品videoxxxx | 久久视频在线观看中文字幕 | 久久久久久网站 | 免费黄色看片 | 99久久精品国 | 成年人电影免费在线观看 | 日本久久不卡视频 | 国产小视频在线 | 一区二区三区在线免费观看 | a视频免费在线观看 | 91色九色 | 777久久久| 中文国产成人精品久久一 | 欧美精品中文在线免费观看 | 精品欧美在线视频 | 99视频在线精品国自产拍免费观看 | 国产aaa大片| 欧美激情综合网 | 91精品国产综合久久福利 | 波多野结衣综合网 | 国产男男gay做爰 | 国产黄色片免费观看 | 成人久久影院 | 久久久久久久久久网 | 婷婷丁香色综合狠狠色 | 久久9999久久免费精品国产 | 亚洲国产经典视频 | 夜夜视频欧洲 | 91精品国产麻豆国产自产影视 | 天天色天天色 | 开心激情五月婷婷 | 欧美日韩综合在线 | 色999精品| 久久免费片 | 新版资源中文在线观看 | 97成人在线免费视频 | 国产18精品乱码免费看 | 久草视频视频在线播放 | 四虎国产精| 久久久久久久电影 | 国产色中涩 | 97人人澡人人添人人爽超碰 | 精品在线免费观看 | 97视频在线观看成人 | 99视频在线精品国自产拍免费观看 | av网站手机在线观看 | 91久久一区二区 | 视频一区二区免费 | 中文字幕91在线 | 亚洲五月| 日韩一区精品 | 久久久久国产精品免费网站 | 人人玩人人添人人 | 日韩在线视频免费看 | 97在线视 | 久久这里精品视频 | 亚洲欧美日韩精品久久久 | 久久天天躁狠狠躁夜夜不卡公司 | 欧美日韩不卡一区二区 | 色综合中文综合网 | 最新av免费在线观看 | 国产精品第一 | 免费av网站观看 | 亚洲免费精彩视频 | 免费观看国产成人 | 免费aa大片 | 日韩久久精品一区二区三区 | 国产字幕av | 日韩在线免费播放 | 亚洲一级电影 | 99九九99九九九视频精品 | 国产资源在线观看 | 国产精品二区在线观看 | 五月天亚洲激情 | 91.精品高清在线观看 | 深爱激情综合网 | 久久精品79国产精品 | 88av色| 九九免费精品视频 | 欧美一级黄色网 | 99久久精品无免国产免费 | 日本精品视频在线观看 | 麻豆传媒视频在线免费观看 | 伊人天天色 | 亚洲一区二区观看 | 精品色综合| 国产韩国日本高清视频 | 久久精品91久久久久久再现 | 99久久日韩精品视频免费在线观看 | 日日麻批40分钟视频免费观看 | 黄色av一区二区三区 | 在线国产不卡 | 永久免费精品视频 | 国产精品久久久久久久av大片 | 97视频在线观看成人 | 久久午夜色播影院免费高清 | 天天干夜夜 | 黄色影院在线免费观看 | 九九综合在线 | 天天摸天天舔天天操 | 国产亚洲精品免费 | 99在线热播精品免费99热 | 国产精品久久久久久久久久久久冷 | 四虎国产精品免费观看视频优播 | 超碰人人在 | 日韩精品免费在线 | 国产成人精品av | 在线视频免费观看 | 伊人五月在线 | 日韩一区二区久久 | 国产一区91 | 五月婷婷色 | mm1313亚洲精品国产 | 免费在线黄色av | 亚洲一级电影 | 日韩中文在线视频 | 色婷婷视频| 又黄又爽又色无遮挡免费 | 4438全国亚洲精品观看视频 | 手机在线观看国产精品 | a级免费观看 | 中文字幕免费一区二区 | 亚洲综合色av | 欧美成人性网 | 亚洲理论电影 | 天天射天天搞 | 成人午夜电影网 | 日韩资源在线 | 午夜私人影院久久久久 | 91女子私密保健养生少妇 | 中文不卡视频 | av永久网址 | 天堂va在线高清一区 | 最近中文字幕在线中文高清版 | 日操干| 激情综合网色播五月 | 久久精品中文字幕免费mv | 操综合| 欧美综合色在线图区 | 三级av在线 | 欧美色综合 | 亚洲欧洲xxxx| 色视频在线观看免费 | 91在线精品一区二区 | 在线免费色 | 国产中文字幕久久 | 中文字幕在线观看一区 | 伊人色综合网 | 国产亚洲精品成人 | 亚洲自拍自偷 | 精品国产99国产精品 | 国产精品第一页在线 | 久久精国产| 亚洲精品456在线播放乱码 | 狠狠干天天射 | 91黄色成人 | 国色天香在线观看 | 国产成人精品久久久 | 97操碰 | 三日本三级少妇三级99 | 黄色片毛片 | 日韩精品欧美一区 | 性色在线视频 | 国产免费一区二区三区最新 | 久久伦理视频 | 在线亚洲观看 | 国产视频亚洲精品 | a天堂中文在线 | 免费黄色在线 | 国产精品一区二区av | 在线观看成人福利 | 日韩网站在线看片你懂的 | 久久久免费观看完整版 | 手机看片国产 | 夜色成人av | www.日本色| 免费亚洲精品 | 狠狠干夜夜操 | 久久精品永久免费 | av亚洲产国偷v产偷v自拍小说 | 亚洲日本va午夜在线电影 | 久草在线视频精品 | 欧美夫妻生活视频 | 国产无限资源在线观看 | 欧美日韩国产伦理 | 精品美女在线视频 | 色婷婷99 | 日韩视频免费看 | 国内精品免费久久影院 | av电影在线免费观看 | av三级在线免费观看 | 在线播放一区 | 久草在线在线视频 | 九九九在线 | 一区二区三区免费在线观看视频 | 久久视频精品在线观看 | 日韩色区 | av线上免费观看 | 国产黄色精品在线观看 | 中文字幕在线观看你懂的 | 精品国产伦一区二区三区观看体验 | 911国产精品 | 狠狠色丁香婷婷综合橹88 | 国产麻豆精品久久一二三 | 久久极品 | 丁香影院在线 | 中文字幕在线国产精品 | 看黄色91| 欧美一级性生活片 | 91麻豆精品国产91久久久使用方法 | 精品成人在线 | 久久国产电影院 | 国产成人精品亚洲 | 日韩免费二区 | 7777xxxx | 国产成人久 | 久久99精品久久久久久久久久久久 | 99精品乱码国产在线观看 | 国产视频97 | 人人看人人草 | 91av在线精品 | 亚洲自拍自偷 | 欧美成人h版在线观看 | 天天透天天插 | 亚洲高清免费在线 | 色五月色开心色婷婷色丁香 | 91天天视频 | 亚洲国产精品电影在线观看 | 久久久久久久久福利 | 免费在线观看的av网站 | 亚洲国产视频网站 | 成人免费视频a | 免费观看成年人视频 | 99在线热播精品免费99热 | 久久九九精品久久 | h动漫中文字幕 | 国产麻豆精品久久 | 成人黄色片在线播放 | 国产精品综合久久久久久 | 亚洲国产精品一区二区久久,亚洲午夜 | 国产一区影院 | 手机版av在线| 波多野结衣一区二区三区中文字幕 | 99在线免费观看视频 | 日韩久久久久久 | 久久一级片 | 99精品国产福利在线观看免费 | 中文字幕资源在线 | 久久中文精品视频 | 96久久欧美麻豆网站 | 国产精品第一页在线 | 亚洲精品国产精品国 | 五月天综合网站 | 国产一区二区在线观看视频 | 精品国产伦一区二区三区免费 | 国产成人1区 | 99视频在线看 | 日本 在线 视频 中文 有码 | www黄| 日本性久久| 中文字幕在线观看完整版电影 | 五月婷婷综合激情网 | 在线观看日本高清mv视频 | 91免费在线视频 | 91精品国产成人观看 | 夜夜操狠狠操 | 午夜在线日韩 | 亚洲精品久 | 日韩在线视频精品 | 在线观看黄色免费视频 | 久久成视频 | 久久综合久色欧美综合狠狠 | 天天操操 | 日本成人a | 精品理论片 | 91大神在线观看视频 | 在线观看免费黄色 | 日韩欧美视频免费在线观看 | 狠狠操欧美| 黄色网在线免费观看 | 五月综合网 | 狠狠躁夜夜躁人人爽超碰91 | 91久色蝌蚪 | 久久手机免费视频 | 欧美了一区在线观看 | 99精品免费 | 五月综合激情网 | 国产日韩中文在线 | 国产精品不卡视频 | 成+人+色综合 | 99色在线视频 | 成人国产精品久久久久久亚洲 | 免费亚洲婷婷 | 成年人免费在线播放 | 91香蕉视频在线 | 国产精品精品久久久久久 | 欧美一级久久 | 又黄又刺激的网站 | aaawww| 极品美女被弄高潮视频网站 | 欧美片网站yy | 五月婷婷在线综合 | 国产69久久久 | 视频在线精品 | 亚洲高清在线视频 | 成人国产精品久久久久久亚洲 | 免费观看v片在线观看 | 狠狠色噜噜狠狠狠狠 | 久久久久国产精品www | 在线观看中文字幕网站 | 久久在线观看视频 | 欧美乱大交 | 国产成人久久精品亚洲 | 91资源在线 | 精品中文字幕视频 | 亚洲成人av片在线观看 | www.色婷婷.com | 日韩v在线91成人自拍 | 五月婷婷色| 久久久久一区 | 综合网欧美 | 亚洲草视频 | 又污又黄网站 | 日日爱av | 国产成人专区 | 日韩乱色精品一区二区 | 精品国产诱惑 | 在线观看亚洲国产 | 日日干干| 在线观看av不卡 | 欧美成人久久 | 一区二区三区四区五区在线 | 欧美成人精品在线 | 最近久乱中文字幕 | 亚洲黄色免费在线 | 亚洲 中文 在线 精品 | 国产日本亚洲高清 | 99免费在线播放99久久免费 | 国产精品一区二区精品视频免费看 | 色多多污污 | 91你懂的| 在线观看视频在线观看 | 99国产精品一区二区 | 一区二区视频播放 | 欧美在线aa | 国产高清视频在线播放 | 日韩精品最新在线观看 | 亚洲第一av在线 | 日韩电影在线观看中文字幕 | 伊人亚洲综合网 | 亚洲精品一区二区精华 | 日本久久成人中文字幕电影 | 中文字幕 国产 一区 | 亚洲国产日韩在线 | 久久免费精品一区二区三区 | www国产亚洲| 久久99久久精品 | 久久这里 | 久久一级片 | 亚洲国产成人久久 | 国产精品白丝jk白祙 | 国产精品毛片久久久久久久久久99999999 | 亚洲一区二区高潮无套美女 | 在线香蕉视频 | 成人午夜电影在线观看 | 亚洲女欲精品久久久久久久18 | 久久九九久久 | 国产美女视频网站 | 国产69久久久| 亚洲免费观看在线视频 | 国内久久视频 | 麻豆传媒一区二区 | 国产精品久久一区二区三区不卡 | 久久精品中文字幕少妇 | 亚洲国产精品视频 | av日韩国产 | 99久久精品久久久久久清纯 | 亚洲精品黄网站 | 精品久久久免费 | 中文av资源站 | 日韩高清观看 | 91天堂影院| 色综合a | 97av影院 | 久久免费福利视频 | 欧美美女一级片 | 久久久久久久久久久精 | 欧美久久久久久久久 | 国产又黄又爽无遮挡 | 韩国精品视频在线观看 | 51久久夜色精品国产麻豆 | 成人h动漫精品一区二 | 亚洲人成人在线 | 你操综合| 国产一级一级国产 | 久久久久久久久久久久影院 | 免费91在线 | 久久精品日产第一区二区三区乱码 | 四虎5151久久欧美毛片 | av字幕在线| 九九精品视频在线观看 | 天天摸天天操天天爽 | 97视频免费在线看 | 亚洲狠狠婷婷 | 99视频| www欧美xxxx| 国内成人综合 | 国产91精品看黄网站 | 人人插人人费 | 日韩一区二区三区免费视频 | 久久久久久久久久网 | 精品在线视频一区二区三区 | 久久精品国产亚洲 | 日本女人的性生活视频 | 国产免费国产 | 911久久香蕉国产线看观看 | 欧美日韩精| 黄色福利网站 | 久久精品视频2 | 亚洲午夜av久久乱码 | 91在线视频导航 | 久久久毛片 | 国产精品自产拍 | 国产美女黄网站免费 | 99婷婷| 国产视频1 | 亚洲精品视频中文字幕 | 中文字幕制服丝袜av久久 | 成人在线免费av | 国产在线观看免费av | 免费av小说| 久久国产精品99国产 | 日韩精品一区二区三区免费视频观看 | 97香蕉超级碰碰久久免费软件 | 精品久久久久久综合日本 | 99激情网 | 成人免费毛片aaaaaa片 | 91久久爱热色涩涩 | 91丨九色丨首页 | 国产精品久久久久久婷婷天堂 | 久久精品国产v日韩v亚洲 | 欧美久久久久久久久久 | 免费在线黄 | 九色最新网址 | 久久你懂得 | 黄网站色欧美视频 | 国产精品网红直播 | 麻豆一区二区三区视频 | 久草在线视频网站 | 久草视频在线免费 | 91麻豆精品国产91久久久久久久久 | 黄网站免费久久 | 国产成人精品免高潮在线观看 | 久久久久久久久久久久久久电影 | 亚洲精品午夜视频 | 极品美女被弄高潮视频网站 | 久久精品视频在线播放 | 欧美性另类 | 嫩草av在线 | 九九在线免费视频 | 日本韩国在线不卡 | 88av色| 91色在线观看 | 狠狠色丁香久久婷婷综合五月 | 五月天亚洲精品 | 天天超碰 | 欧美黑吊大战白妞欧美 | 国产日韩欧美综合在线 | 亚洲 综合 精品 | www.亚洲激情.com | 国产福利精品视频 | 香蕉视频在线播放 | 久久精品超碰 | 国产精品一区二区免费视频 | 亚洲国产精品免费 | 亚洲美女精品区人人人人 | 国产原创av在线 | 成人av午夜 | 久久爱资源网 | 在线观看你懂的网址 | 男女视频久久久 | 最新中文字幕 | 国产麻豆剧果冻传媒视频播放量 | 国产精品成人a免费观看 | 天天搞夜夜骑 | 精品电影一区 | 久久理论视频 | 成人av资源 | 亚洲免费av网站 | 在线亚洲午夜片av大片 | 精品国产久 | 丁香婷婷色月天 | 国产精品免费麻豆入口 | 成人av亚洲 | 久久久久激情电影 | 免费观看mv大片高清 | 亚洲午夜精品在线观看 | 蜜桃av人人夜夜澡人人爽 | 国产一级免费视频 | 97伊人网| 天天干夜夜夜 | 日日干激情五月 | 中文字幕中文字幕中文字幕 | 国产香蕉视频在线播放 | 人人爽人人| 99久久久国产精品免费99 | 欧美黄网站 | 日韩中文字幕免费视频 | 狠狠色丁香久久综合网 | 69视频在线播放 | 久久久污 | 欧美人交a欧美精品 | 日本久久精品 | 国产精品99久久久久久久久 | 欧美在线久久 | 日本黄色大片免费 | 欧美性色综合网 | 91亚·色| 91在线观| 国产视频久久久 | 97超碰国产精品 | 视频一区视频二区在线观看 | 一本之道乱码区 | 日韩精品视 | 四虎5151久久欧美毛片 | 亚洲精品毛片一级91精品 | 久久电影中文字幕视频 | 69av在线播放 | 久草在线在线精品观看 | 久久色视频 | 精品国内自产拍在线观看视频 | 一区免费视频 | 欧美色图30p| 99热这里只有精品国产首页 | 九九三级毛片 | 国产精品久久电影网 | 在线不卡的av | 免费网站黄色 | 在线观看一区二区精品 | 在线观看91av| 91麻豆看国产在线紧急地址 | 欧美一级性生活片 | 激情综合网五月婷婷 | 免费高清男女打扑克视频 | 三级在线国产 | 国产美女精品视频免费观看 | 亚洲国产影院 | 国产亚洲欧美在线视频 | 国内精品毛片 | 97精品国自产拍在线观看 | 国产精品麻豆99久久久久久 | 日韩在线第一 | 免费在线观看av不卡 | 久久99精品久久久久久清纯直播 | 五月婷婷中文字幕 | 四虎在线视频免费观看 | 麻豆91精品91久久久 | 中国一级片视频 | 开心激情五月婷婷 | 欧美视频在线二区 | 日韩乱码在线 | 黄色三级免费片 | 在线亚洲小视频 | 九九久久久 | 又色又爽的网站 | 久久精品精品电影网 | 免费看的黄色 | 一区二区欧美激情 | 激情综合站 | 三级黄色欧美 | 亚洲高清在线观看视频 | 日韩欧美视频一区二区 | 日韩在线看片 | 亚洲欧美在线综合 | 国产精品免费人成网站 | 超碰在线cao | 一区二区三区视频网站 | 六月色丁香| 精选久久 | 91福利区一区二区三区 | 日韩中文字幕免费电影 | 婷婷丁香导航 | 亚洲一区二区三区精品在线观看 | 又黄又爽免费视频 | 欧美大jb| 一区二区精品在线 | 欧美极品xxxx | 一区二区三区不卡在线 | 天天干天天摸天天操 | 成年人毛片在线观看 | 国产亚洲精品成人av久久影院 | 中文字幕精品一区二区精品 | 精品一区二区影视 | 视频一区在线免费观看 | 国产日韩精品在线观看 | 91色吧 | 久久区二区 | 亚洲尺码电影av久久 | 中文一区二区三区在线观看 | 国产精品久久久久久久久久久免费看 | 欧美久久久久久久 | 91亚洲精品久久久 | 中文字幕麻豆 | 欧美色图视频一区 | 色综合久久88色综合天天人守婷 | 人人爽人人爽人人 | 精品国产免费人成在线观看 | 久久视频网 | 国产精品永久免费观看 | 国产日韩在线一区 | 欧美日韩亚洲在线观看 | 国产精品欧美一区二区三区不卡 | 69久久99精品久久久久婷婷 | 波多野结衣视频网址 | 亚洲成年人免费网站 | 国产精品综合久久久 | 成人黄色毛片视频 | 久久亚洲欧美日韩精品专区 | 欧美激情视频一区二区三区免费 | 夜夜操夜夜干 | 精品久久久久久久久久 | 波多野结衣一区三区 | 天天操比 | 黄网站色欧美视频 | 亚洲精品乱码久久久久久蜜桃欧美 | a√资源在线 | 一二三区高清 | 天天av在线播放 | 99视| 91麻豆免费看 | 精品黄色片| 91色综合 | 国产精品久久久久久久午夜 | 麻花天美星空视频 | 免费精品国产 | 亚洲成人黄色 | 国产午夜在线 | 久久久精品电影 | 久久区二区 | 婷婷色在线播放 | 午夜精品电影 | 丁香久久激情 | 国产亚洲观看 | 欧洲一区二区在线观看 | 国产高清久久 | 三级av免费看 | 婷婷在线色| 国产一区欧美一区 | 国产小视频在线 | 91试看 | 久久av不卡| 天天射夜夜爽 | 亚洲精品午夜久久久久久久久久久 | 日本中文字幕系列 | 久久怡红院 | 亚洲国产成人久久综合 | 92精品国产成人观看免费 | 日本h视频在线观看 | 欧美性精品 | 亚洲精品久久久久久中文传媒 | 在线免费观看一区二区三区 | 欧美日韩高清在线一区 | 久艹在线观看视频 | 精品久久一级片 | 中文字幕第一页在线播放 | www国产在线 | av在线播放网址 | 国产精品成人一区二区 | 欧美性色综合网站 | 人人添人人澡人人澡人人人爽 | 欧美va电影| 亚洲综合成人专区片 | 亚洲综合涩 | 成人在线免费视频观看 | 亚洲综合导航 | 天堂网中文在线 | 中文在线字幕免费观 | 在线看片一区 | 亚洲精品乱码久久久久久蜜桃91 | 91精品一区国产高清在线gif | 国产剧在线观看片 | 免费观看的黄色 | 亚洲精品在线一区二区三区 | 一区二区三区高清在线 | 成人国产精品一区二区 | 日本xxxx.com| 狠狠干综合网 | 69精品 | 青青久视频 | 久久午夜免费观看 | 黄色一区二区在线观看 | 91网在线观看 | 精品国产aⅴ一区二区三区 在线直播av | 91精品国产福利 | 黄色网址中文字幕 | 欧美激情一区不卡 | 日韩色区 | 国产91勾搭技师精品 | 中文av日韩 | 日韩视频一区二区 | 天天爱天天舔 | 日韩免费高清在线 | 久草国产在线观看 | 成 人 黄 色视频免费播放 | 国产99久久久国产精品免费二区 | 久久久久成人精品亚洲国产 | 91九色最新地址 | 国产精品永久久久久久久久久 | 在线一级片| 四虎在线观看精品视频 | 波多野结衣资源 | 日韩电影中文 | 欧美日韩裸体免费视频 | 胖bbbb搡bbbb擦bbbb | 久久不卡国产精品一区二区 | 人人爱夜夜操 | 精品久久精品 | 亚洲视频在线观看网站 | 在线一区电影 | 亚洲精品国产精品国产 | 91免费视频网站在线观看 | 国产麻豆视频在线观看 | 婷婷爱五月天 | 国产精品观看视频 | 久久女同性恋中文字幕 | 在线观看视频免费大全 | 国产在线一卡 | 亚洲精品成人免费 | 国产91勾搭技师精品 | 99久久日韩精品视频免费在线观看 | 成人福利在线 | 免费看的黄色的网站 | 国产日韩欧美综合在线 | 亚洲激精日韩激精欧美精品 | 国产自在线观看 | 在线观看精品一区 | 国产成人一区二区三区在线观看 | 久久精品电影 | 国产免费资源 | 一区二区三区视频网站 | japanesefreesexvideo高潮| 日日干天天插 | 久久精品一二三区 | 在线观看中文字幕一区二区 | 蜜臀久久99精品久久久酒店新书 | 日韩毛片一区 | 亚洲视频在线观看 | 天天操天天操天天 | 日韩美女久久 | 最新不卡av | 中文字幕丰满人伦在线 | 国产精品高清在线 | 欧美亚洲一级片 | 久人人| 热99在线视频 | 久久特级毛片 | 成人片在线播放 | 欧美日韩在线视频一区 | 国内综合精品午夜久久资源 | 久草视频精品 | 香蕉在线观看视频 | 精品国产a | 午夜精品剧场 | 丰满少妇一级 | 日韩在线高清免费视频 | 91视频久久 | 国产一级久久久 | 中文字幕在线观看免费高清完整版 | 婷婷六月丁 | 日日夜夜骑 | 日本女人的性生活视频 | 手机成人av在线 | 免费合欢视频成人app | 久久免费视频在线观看 | 五月天狠狠操 | 国产精品久久久久一区二区三区 | 一本大道久久精品懂色aⅴ 五月婷社区 | 国产一区不卡在线 | 九九久久在线看 | 91成人免费在线 | 黄色av电影免费观看 | 日批视频在线观看免费 | 狠狠操狠狠干天天操 | 香蕉影院在线观看 | 麻豆视频免费入口 | 这里只有精品视频在线 | 久久视频二区 | 成人网中文字幕 | 91精品久久久久久久久久入口 | 丁香六月av| 免费视频色| 国产福利一区二区三区在线观看 | 精品在线你懂的 | 在线天堂v | 国产精品视频久久久 | 天天干天天干天天干 | 中文字幕国语官网在线视频 | 91精品国产91久久久久福利 | 国产精品久久久久久久久久免费看 | 色综合久久88色综合天天人守婷 | 天堂在线免费视频 | 视频一区视频二区在线观看 | 高清中文字幕av | 亚洲综合国产精品 | 日韩欧美视频免费在线观看 | 亚洲欧美视频一区二区三区 | 欧美三级高清 | 狠狠狠狠狠狠狠干 |