runloop理解

原文的介紹http://www.cocoachina.com/ios/20150601/11970.html

1.runloop是來(lái)做什么的碉输?runloop和線程有什么關(guān)系?主線程默認(rèn)開(kāi)啟了runloop么啦扬?子線程呢类缤?
runloop:這是個(gè)對(duì)象在程序運(yùn)行過(guò)程中通過(guò)循環(huán)跑圈來(lái)處理線程里面的事件和消息恭垦,從而保持程序的持續(xù)運(yùn)行圈匆;而且在沒(méi)有事件處理的時(shí)候漠另,會(huì)進(jìn)入睡眠模式,從而節(jié)省CPU資源跃赚,提高程序性能
runloop和線程的關(guān)系:線程在處理完自己的任務(wù)后一般會(huì)退出笆搓,為了實(shí)現(xiàn)線程不退出能夠隨時(shí)處理任務(wù),不被釋放纬傲,就必須有一個(gè)runloop來(lái)不停的跑圈满败;線程和runloop是一一對(duì)應(yīng)的,關(guān)系保存在全局字典里叹括;線程創(chuàng)建時(shí)并沒(méi)有RunLoop算墨,(主線程除外),RunLoop不能創(chuàng)建汁雷,只能主動(dòng)獲取才會(huì)有净嘀。RunLoop的創(chuàng)建是在第一次獲取時(shí),RunLoop的銷毀是發(fā)生在線程結(jié)束時(shí)侠讯。只能在一個(gè)線程中獲取自己和主線程的RunLoop挖藏。
主線程默認(rèn)是開(kāi)啟一個(gè)runloop。也就是這個(gè)runloop才能保證我們程序正常的運(yùn)行继低。子線程是默認(rèn)沒(méi)有開(kāi)始runloop的

  1. runloop創(chuàng)建原理(與線程得關(guān)系)和內(nèi)部實(shí)現(xiàn)原理
runloop創(chuàng)建原理
// 全局的Dictionary熬苍,key 是 pthread_t, value 是 CFRunLoopRef 
static CFMutableDictionaryRef loopsDic; 
// 訪問(wèn) loopsDic 時(shí)的鎖 
static CFSpinLock_t loopsLock; 
// 獲取一個(gè) pthread 對(duì)應(yīng)的 RunLoop袁翁。 
CFRunLoopRef _CFRunLoopGet(pthread_t thread) {    
 OSSpinLockLock(&loopsLock);     
if (!loopsDic) {         
// 第一次進(jìn)入時(shí)柴底,初始化全局Dic,并先為主線程創(chuàng)建一個(gè) RunLoop粱胜。         
loopsDic = CFDictionaryCreateMutable();       
  CFRunLoopRef mainLoop = _CFRunLoopCreate();        
 CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);     
}     
// 直接從 Dictionary 里獲取柄驻。     
CFRunLoopRef loop = CFDictionaryGetValue(loopsDic, thread));     
if (!loop) {         
// 取不到時(shí),創(chuàng)建一個(gè)         
loop = _CFRunLoopCreate();        
CFDictionarySetValue(loopsDic, thread, loop);         
// 注冊(cè)一個(gè)回調(diào)焙压,當(dāng)線程銷毀時(shí)鸿脓,順便也銷毀其對(duì)應(yīng)的 RunLoop。         
_CFSetTSD(..., thread, loop, __CFFinalizeRunLoop);     
}     
OSSpinLockUnLock(&loopsLock);     
return loop; 
} 
CFRunLoopRef CFRunLoopGetMain() {     
return _CFRunLoopGet(pthread_main_thread_np()); 
} 
CFRunLoopRef CFRunLoopGetCurrent() {     
return _CFRunLoopGet(pthread_self()); 
}

runloop運(yùn)行原理(這種模型通常被稱作 Event Loop):
對(duì)事件源做判斷涯曲,有就通過(guò)相應(yīng)的函數(shù)返回野哭,沒(méi)有就往下執(zhí)行,直到mach.msg進(jìn)入休眠并等待喚醒幻件。mach是內(nèi)核的核心拨黔,提供了進(jìn)程間通信(以消息的形式來(lái)完成)和處理器調(diào)度等基本服務(wù),消息的發(fā)送和接收使用<mach/message.h>中的mach_msg()函數(shù)绰沥,所以runloop的喚醒和休眠是系統(tǒng)完成的篱蝇。
RunLoop是一個(gè)對(duì)象并提供了do-while循環(huán)執(zhí)行的一個(gè)入口函數(shù)贺待,當(dāng)線程執(zhí)行了這個(gè)函數(shù)后,就會(huì)一直處于這個(gè)函數(shù)內(nèi)部 "接受消息->等待->處理" 的循環(huán)中零截,runloop在循環(huán)執(zhí)行得過(guò)程中通過(guò)CFRunLoopObserverRef監(jiān)聽(tīng)runloop狀態(tài)的改變麸塞,然后調(diào)用source/time/observer的回調(diào)函數(shù),完成事件處理涧衙;直到超時(shí)或被手動(dòng)停止哪工,該函數(shù)才會(huì)返回。
一個(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,讓其互不影響两踏。
source0和source1的區(qū)別:
Source0(負(fù)責(zé)App內(nèi)部事件败京,由App負(fù)責(zé)管理觸發(fā),例如UITouch事件)梦染,只包含了一個(gè)回調(diào)(函數(shù)指針)赡麦,它并不能主動(dòng)觸發(fā)事件。使用時(shí)帕识,你需要先調(diào)用 CFRunLoopSourceSignal(source)泛粹,將這個(gè) Source 標(biāo)記為待處理 signal 狀態(tài),然后手動(dòng)調(diào) CFRunLoopWakeUp(runloop) 來(lái)喚醒 RunLoop肮疗,讓其處理這個(gè)事件证薇。
Source1除了包含回調(diào)指針外包含一個(gè)mach port馏谨,Source1可以監(jiān)聽(tīng)系統(tǒng)端口和其他線程相互發(fā)送消息恕齐,它能夠主動(dòng)喚醒RunLoop(由操作系統(tǒng)內(nèi)核進(jìn)行管理踩官,例如CFMessagePort消息)。
事件:觸摸事件(用戶交互事件)碱呼、時(shí)鐘事件(timer)蒙挑、網(wǎng)絡(luò)事件、系統(tǒng)內(nèi)核事件

1愚臀,  runloop得五個(gè)類
CFRunLoopRef  //獲得當(dāng)前RunLoop和主RunLoop 
CFRunLoopModeRef  //運(yùn)行模式脆荷,只能選擇一種,在不同模式中做不同的操作 
CFRunLoopSourceRef  //事件源,輸入源 (是事件產(chǎn)生的地方蜓谋。) 
Source0 只包含了一個(gè)回調(diào)(函數(shù)指針),它并不能主動(dòng)觸發(fā)事件炭分。使用時(shí)桃焕,你需要先調(diào)用 CFRunLoop-SourceSignal(source),將這個(gè) Source 標(biāo)記為待處理捧毛,然后手動(dòng)調(diào)用 CFRunLoop-WakeUp(runloop) 來(lái)喚醒 RunLoop观堂,讓其處理這個(gè)事件。
Source1 包含了一個(gè) mach_port 和一個(gè)回調(diào)(函數(shù)指針)呀忧,被用于通過(guò)內(nèi)核和其他線程相互發(fā)送消息师痕。這種 Source 能主動(dòng)喚醒 RunLoop 的線程,其原理在下面會(huì)講到而账。
CFRunLoopTimerRef //是基于時(shí)間的觸發(fā)器胰坟,它和 NSTimer 是toll-free bridged 的,可以混用泞辐。其包含一個(gè)時(shí)間長(zhǎng)度和一個(gè)回調(diào)(函數(shù)指針)笔横。當(dāng)其加入到 RunLoop 時(shí),RunLoop會(huì)注冊(cè)對(duì)應(yīng)的時(shí)間點(diǎn)咐吼,當(dāng)時(shí)間點(diǎn)到時(shí)吹缔,RunLoop會(huì)被喚醒以執(zhí)行那個(gè)回調(diào)。
CFRunLoopObserverRef //觀察者是觀察者锯茄,每個(gè) Observer 都包含了一個(gè)回調(diào)(函數(shù)指針)厢塘,當(dāng) RunLoop 的狀態(tài)發(fā)生變化時(shí),觀察者就能通過(guò)回調(diào)接受到這個(gè)變化肌幽⊥砟耄可以觀測(cè)的時(shí)間點(diǎn)有以下幾個(gè):
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry         = (1UL << 0), // 即將進(jìn)入Loop
    kCFRunLoopBeforeTimers  = (1UL << 1), // 即將處理 Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即將處理 Source
    kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進(jìn)入休眠
    kCFRunLoopAfterWaiting  = (1UL << 6), // 剛從休眠中喚醒
    kCFRunLoopExit          = (1UL << 7), // 即將退出Loop
};
CFRunLoopModeRef
系統(tǒng)默認(rèn)注冊(cè)了5個(gè)Mode:
kCFRunLoopDefaultMode:App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行
UITrackingRunLoopMode:界面跟蹤 Mode牍颈,用于 ScrollView 追蹤觸摸滑動(dòng)迄薄,保證界面滑動(dòng)時(shí)不受其他 Mode 影響
UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode,啟動(dòng)完成后就不再使用
GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode煮岁,通常用不到
kCFRunLoopCommonModes: 這是一個(gè)占位用的Mode讥蔽,不是一種真正的Mode
滑動(dòng)UI時(shí)NSTimer不能工作:當(dāng)NSTimer運(yùn)行在NSDefaultRunLoopMode下的時(shí)候會(huì)因?yàn)镽unLoopMode的改變而無(wú)法正常工作。需要切換到NSRunLoopCommonModes才能保證NSTimer在NSDefaultRunLoopMode和UITrackingRunLoopMode下正常工作画机。
2冶伞,CFRunLoopMode 和 CFRunLoop 的結(jié)構(gòu)
```
struct __CFRunLoopMode {
    CFStringRef _name;            // Mode Name, 例如 @"kCFRunLoopDefaultMode"
    CFMutableSetRef _sources0;    // Set 
    CFMutableSetRef _sources1;    // Set 
    CFMutableArrayRef _observers; // Array 
    CFMutableArrayRef _timers;    // Array 
    ...
};

struct __CFRunLoop {
    CFMutableSetRef _commonModes;     // Set 
    CFMutableSetRef _commonModeItems; // Set 
    CFRunLoopModeRef _currentMode;    // Current Runloop Mode
    CFMutableSetRef _modes;           // Set 
    ...
};
runloop內(nèi)部代碼實(shí)現(xiàn)如下 
在開(kāi)發(fā)過(guò)程中幾乎所有的操作都是通過(guò)Call out進(jìn)行回調(diào)的
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__();
    static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__();
    static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__();
    static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__();
    static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__();
    static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__();

/// 用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)mode
    CFRunLoopModeRef 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);
            /// 處理非延遲的主線程調(diào)用
            __CFRunLoopDoBlocks(runloop, currentMode);
             
            /// 4. RunLoop 觸發(fā) Source0 (非port) 回調(diào)隆嗅。
            sourceHandledThisLoop = __CFRunLoopDoSources0(runloop, currentMode, stopAfterHandle);
        if (sourceHandledThisLoop) {
            __CFRunLoopDoBlocks();
         }
            /// 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);
}
runloop運(yùn)行原理.png

3搬瑰,舉例說(shuō)明
AutoreleasePool:App啟動(dòng)后,,系統(tǒng)在主線程RunLoop 里注冊(cè)兩個(gè)Observser,其回調(diào)都是_wrapRunLoopWithAutoreleasePoolHandler()。
第一個(gè) Observer 監(jiān)視的事件是 Entry(即將進(jìn)入Loop),其回調(diào)內(nèi)會(huì)調(diào)用 _objc_autoreleasePoolPush() 創(chuàng)建自動(dòng)釋放池控硼。其優(yōu)先級(jí)最高,保證創(chuàng)建釋放池發(fā)生在其他所有回調(diào)之前泽论。
第二個(gè) Observer 監(jiān)視了兩個(gè)事件: BeforeWaiting(準(zhǔn)備進(jìn)入休眠) 時(shí)調(diào)用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 釋放舊的池并創(chuàng)建新池;Exit(即將退出Loop) 時(shí)調(diào)用 _objc_autoreleasePoolPop() 來(lái)釋放自動(dòng)釋放池。這個(gè) Observer 優(yōu)先級(jí)最低,保證其釋放池子發(fā)生在其他所有回調(diào)之后卡乾。
在主線程執(zhí)行的代碼,通常是寫(xiě)在諸如事件回調(diào)翼悴、Timer回調(diào)內(nèi)的。這些回調(diào)會(huì)被 RunLoop 創(chuàng)建好的 AutoreleasePool 環(huán)繞著,所以不會(huì)出現(xiàn)內(nèi)存泄漏,開(kāi)發(fā)者也不必顯示創(chuàng)建 Pool 了幔妨。

事件相應(yīng):蘋(píng)果注冊(cè)了一個(gè) Source1 (基于 mach port 的) 用來(lái)接收系統(tǒng)事件鹦赎,其回調(diào)函數(shù)為 __IOHIDEventSystemClientQueueCallback()。當(dāng)事件觸發(fā)后經(jīng)過(guò)系統(tǒng)內(nèi)核一系列響應(yīng)后通過(guò)mach port轉(zhuǎn)發(fā)給需要的進(jìn)程误堡,隨后蘋(píng)果注冊(cè)的那個(gè) Source1 就會(huì)觸發(fā)回調(diào)古话,并調(diào)用 _UIApplicationHandleEventQueue() 進(jìn)行應(yīng)用內(nèi)部的分發(fā)。然后就是找到第一響應(yīng)對(duì)象然后就是響應(yīng)锁施。

手勢(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)記為待處理。蘋(píng)果注冊(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)處理。

界面更新:當(dāng)在操作 UI 時(shí)栅螟,比如改變了 Frame、更新了 UIView/CALayer 的層次時(shí)篱竭,或者手動(dòng)調(diào)用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后力图,這個(gè) UIView/CALayer 就被標(biāo)記為待處理,并被提交到一個(gè)全局的容器去掺逼。蘋(píng)果注冊(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 界面赘那。

GCD: 當(dāng)調(diào)用 dispatch_async(dispatch_get_main_queue(), block) 時(shí),libDispatch 會(huì)向主線程的 RunLoop 發(fā)送消息氯质,RunLoop會(huì)被喚醒募舟,并從消息中取得這個(gè) block,并在回調(diào) CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE() 里執(zhí)行這個(gè) block闻察。

PerformSelecter:當(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ì)失效呢灶。


runloop內(nèi)部實(shí)現(xiàn).png

runloop

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钉嘹,隨后出現(xiàn)的幾起案子鸯乃,更是在濱河造成了極大的恐慌,老刑警劉巖跋涣,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缨睡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡仆潮,警方通過(guò)查閱死者的電腦和手機(jī)宏蛉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)性置,“玉大人拾并,你說(shuō)我怎么就攤上這事。” “怎么了嗅义?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵屏歹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我之碗,道長(zhǎng)蝙眶,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任褪那,我火速辦了婚禮幽纷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘博敬。我一直安慰自己友浸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布偏窝。 她就那樣靜靜地躺著收恢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祭往。 梳的紋絲不亂的頭發(fā)上伦意,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音硼补,去河邊找鬼驮肉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛括勺,可吹牛的內(nèi)容都是我干的缆八。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼疾捍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奈辰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起乱豆,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤奖恰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后宛裕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瑟啃,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年揩尸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛹屿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡岩榆,死狀恐怖错负,靈堂內(nèi)的尸體忽然破棺而出坟瓢,到底是詐尸還是另有隱情,我是刑警寧澤犹撒,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布折联,位于F島的核電站,受9級(jí)特大地震影響识颊,放射性物質(zhì)發(fā)生泄漏诚镰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一祥款、第九天 我趴在偏房一處隱蔽的房頂上張望清笨。 院中可真熱鬧,春花似錦刃跛、人聲如沸函筋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至首懈,卻和暖如春绊率,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背究履。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工滤否, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人最仑。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓藐俺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親泥彤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子欲芹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,438評(píng)論 0 13
  • 前言 RunLoop是iOS和OSX開(kāi)發(fā)中非常基礎(chǔ)的一個(gè)概念吟吝,這篇文章將從CFRunLoop的源碼入手菱父,介紹Run...
    暮年古稀ZC閱讀 2,243評(píng)論 1 19
  • RunLoop 的概念 一般來(lái)講,一個(gè)線程一次只能執(zhí)行一個(gè)任務(wù)剑逃,執(zhí)行完成后線程就會(huì)退出浙宜。如果我們需要一個(gè)機(jī)制,讓線...
    Mirsiter_魏閱讀 618評(píng)論 0 2
  • 1 Runloop機(jī)制原理 深入理解RunLoop http://www.cocoachina.com/ios/2...
    Kevin_Junbaozi閱讀 4,013評(píng)論 4 30
  • 每晚都是一個(gè)很愜意的時(shí)刻蛹磺,可以做分享粟瞬,也可以聊聊天∮├Γ或許這就是所謂的自己的空間吧裙品。下了這個(gè)APP俗批,每天沒(méi)...
    呂行者LV閱讀 139評(píng)論 0 0