Runloop

Runloop

什么是runloop

Runloop是通過(guò)內(nèi)部維護(hù)的事件循環(huán) 來(lái)對(duì)事件/消息進(jìn)行管理的一個(gè)對(duì)象

Event Loop:

  • 沒(méi)有消息需要處理時(shí),休眠以避免資源占用 用戶態(tài)->內(nèi)核態(tài)
  • 有消息需要處理時(shí),立刻被喚醒 內(nèi)核態(tài)->用戶態(tài)

runloop對(duì)象

CoreFoundation-CFRunloop
Foundation - NSRunloop
NSRunLoop實(shí)際上是CFRunLoop的高層抽象,CFRunloop是線程安全的,NSRunloop非線程安全.
CFRunloop是開(kāi)源的:https://opensource.apple.com/source/CF/CF-1151.16/

//Foundation
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對(duì)象
[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對(duì)象

//Core Foundation
CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對(duì)象
CFRunLoopGetMain(); // 獲得主線程的RunLoop對(duì)象

開(kāi)啟runloop

- (void)run;
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
- (void)runUntilDate:(NSDate *)limitDate;

run方法對(duì)應(yīng)上面CFRunloopRef中的CFRunLoopRun并不會(huì)退出催束,除非調(diào)用CFRunLoopStop();通常如果想要永遠(yuǎn)不會(huì)退出RunLoop才會(huì)使用此方法胜嗓,否則可以使用runUntilDate。
runMode:beforeDate:則對(duì)應(yīng)CFRunLoopRunInMode(mode,limiteDate,true)方法,只執(zhí)行一次篮愉,執(zhí)行完就退出滩届;通常用于手動(dòng)控制RunLoop(例如在while循環(huán)中)集侯。
runUntilDate:方法其實(shí)是CFRunLoopRunInMode(kCFRunLoopDefaultMode,limiteDate,false),執(zhí)行完并不會(huì)退出帜消,繼續(xù)下一次RunLoop直到timeout棠枉。

runloop與線程

一般來(lái)說(shuō),線程同一時(shí)間只能執(zhí)行一個(gè)任務(wù),任務(wù)執(zhí)行完畢線程就會(huì)被銷(xiāo)毀.每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象。RunLoop 和線程的一一對(duì)應(yīng)關(guān)系保存一個(gè)全局 Dictionary 里 __CFRunLoops.主線程的RunLoop是自動(dòng)創(chuàng)建的(使主線程不被銷(xiāo)毀保證了程序的運(yùn)行而不退出)泡挺,子線程的RunLoop需要手動(dòng)創(chuàng)建CFRunLoopGetCurrent(),在第一次獲取時(shí)創(chuàng)建辈讶,在線程結(jié)束時(shí)銷(xiāo)毀。蘋(píng)果未提供手動(dòng)創(chuàng)建runloop的API,

在UIApplicationMain函數(shù)中娄猫,實(shí)際就是開(kāi)啟了一個(gè)和主線程相關(guān)的RunLoop贱除,導(dǎo)致UIApplicationMain不會(huì)返回,一直在運(yùn)行中媳溺,也就保證了程序的持續(xù)運(yùn)行月幌。

Runloop機(jī)制

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

  • CFRunLoopRef //獲得當(dāng)前RunLoop和主RunLoop
  • CFRunLoopModeRef //運(yùn)行模式,只能選擇一種悬蔽,在不同模式中做不同的操作,且運(yùn)行必須有指定的Mode
  • CFRunLoopSourceRef //事件源扯躺,輸入源
  • CFRunLoopTimerRef //定時(shí)器時(shí)間
  • CFRunLoopObserverRef //觀察者

CFRunLoopRef

typedef struct __CFRunLoop * CFRunLoopRef;

struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock;            /* locked for accessing mode list */
__CFPort _wakeUpPort;            // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData;              // reset for runs of the run loop
pthread_t _pthread; //和線程一對(duì)一的關(guān)系
uint32_t _winthread;
CFMutableSetRef _commonModes; // 字符串,記錄所有標(biāo)記為common的mode
CFMutableSetRef _commonModeItems; // 所有commonMode的item(source蝎困、timer录语、observer)
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes; // CFRunLoopModeRef set
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFTypeRef _counterpart;
};

? CFRunLoop 里面包含了線程,若干個(gè) mode禾乘。
? CFRunLoop 和線程是一一對(duì)應(yīng)的澎埠。
? _blocks_head 是 perform block 加入到里面的

CFRunLoopMode

// 定義 CFRunLoopModeRef 為指向 __CFRunLoopMode 結(jié)構(gòu)體的指針
typedef struct __CFRunLoopMode *CFRunLoopModeRef;

struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock;    /* must have the run loop locked before locking this */
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0; // source0 set ,非基于Port的始藕,接收點(diǎn)擊事件蒲稳,觸摸事件等APP 內(nèi)部事件
CFMutableSetRef _sources1; // source1 set氮趋,基于Port的,通過(guò)內(nèi)核和其他線程通信弟塞,接收凭峡,分發(fā)系統(tǒng)事件
CFMutableArrayRef _observers; // observer 數(shù)組
CFMutableArrayRef _timers; // timer 數(shù)組
CFMutableDictionaryRef _portToV1SourceMap;// source1 對(duì)應(yīng)的端口號(hào)
__CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};

通過(guò)CFRunloopRef對(duì)應(yīng)結(jié)構(gòu)體的定義可以知道每種Runloop都包含若干個(gè)(1:N)Mode,每個(gè)Mode又包含若干(1:N)Source/Timer/Observer决记。Runloop總是運(yùn)行在某種特定的CFRunLoopModeRef下,當(dāng)切換Mode時(shí)必須退出當(dāng)前Mode,然后重新進(jìn)入Runloop以保證不同Mode的Source/Timer/Observer互不影響倍踪。

系統(tǒng)默認(rèn)提供的Run Loop Modes有kCFRunLoopDefaultMode(NSDefaultRunLoopMode)和UITrackingRunLoopMode系宫,需要切換到對(duì)應(yīng)的Mode時(shí)只需要傳入對(duì)應(yīng)的名稱(chēng)即可。前者是系統(tǒng)默認(rèn)的Runloop Mode建车,例如進(jìn)入iOS程序默認(rèn)不做任何操作就處于這種Mode中扩借,此時(shí)滑動(dòng)UIScrollView,主線程就切換Runloop到到UITrackingRunLoopMode缤至,不再接受其他事件操作(除非你將其他Source/Timer設(shè)置到UITrackingRunLoopMode下)潮罪。
kCFRunLoopCommonModes(NSRunLoopCommonModes),這個(gè)并不是某種具體的Mode,而是一種模式組合领斥,在iOS系統(tǒng)中默認(rèn)包含了NSDefaultRunLoopMode和 UITrackingRunLoopMode,是同步Source,Timer,Observer到多個(gè)Mode中的一種技術(shù)方案(注意:并不是說(shuō)Runloop會(huì)運(yùn)行在kCFRunLoopCommonModes這種模式下嫉到,而是相當(dāng)于分別注冊(cè)了 NSDefaultRunLoopMode和 UITrackingRunLoopMode。當(dāng)然你也可以通過(guò)調(diào)用CFRunLoopAddCommonMode()方法將自定義Mode放到 kCFRunLoopCommonModes組合)月洛。

RunLoopSource

runloop3.jpg

RunLoopSource 分為 source0 和 source1何恶。

  • source0 是非基于 port 的事件,主要是 APP 內(nèi)部事件嚼黔,如點(diǎn)擊事件细层,觸摸事件等 需要手動(dòng)喚醒線程
  • source1 是基于Port的唬涧,通過(guò)內(nèi)核和其他線程通信疫赎,接收,分發(fā)系統(tǒng)事件碎节。具備喚醒線程的能力
  • CFRunLoopSource 里面包含一個(gè) _runLoops捧搞,也就意味著一個(gè) CFRunLoopSource 可以被添加到多個(gè) runloop mode 中去。
  • Source1在處理的時(shí)候會(huì)分發(fā)一些操作給Source0去處理
    Source0(負(fù)責(zé)App內(nèi)部事件钓株,由App負(fù)責(zé)管理觸發(fā)实牡,例如UITouch事件)和Timer(又叫Timer Source,基于時(shí)間的觸發(fā)器轴合,上層對(duì)應(yīng)NSTimer)是兩個(gè)不同的Runloop事件源(當(dāng)然Source0是Input Source中的一類(lèi)创坞,Input Source還包括Custom Input Source,由其他線程手動(dòng)發(fā)出)受葛,RunLoop被這些事件喚醒之后就會(huì)處理并調(diào)用事件處理方法(CFRunLoopTimerRef的回調(diào)指針和CFRunLoopSourceRef均包含對(duì)應(yīng)的回調(diào)指針)题涨。
    Source1除了包含回調(diào)指針外包含一個(gè)mach port偎谁,和Source0需要手動(dòng)觸發(fā)不同,Source1可以監(jiān)聽(tīng)系統(tǒng)端口和其他線程相互發(fā)送消息纲堵,它能夠主動(dòng)喚醒RunLoop(由操作系統(tǒng)內(nèi)核進(jìn)行管理巡雨,例如CFMessagePort消息)。官方也指出可以自定義Source席函,因此對(duì)于CFRunLoopSourceRef來(lái)說(shuō)它更像一種協(xié)議铐望,框架已經(jīng)默認(rèn)定義了兩種實(shí)現(xiàn),如果有必要開(kāi)發(fā)人員也可以自定義.

RunLoopTimer

  • CFRunLoopTimer 是基于事件的定時(shí)器茂附,可以在設(shè)定的時(shí)間點(diǎn)拋出回調(diào)
  • CFRunLoopTimer和NSTimer是toll-free bridged的正蛙,可以相互轉(zhuǎn)換。

CFRunLoopObserver

觀察者营曼,可以觀察RunLoop的各種狀態(tài)乒验,并拋出回調(diào)〉仝澹可以監(jiān)聽(tīng)的狀態(tài)如下:

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 進(jìn)入RunLoop
kCFRunLoopBeforeTimers = (1UL << 1), // 即將開(kāi)始Timer處理
kCFRunLoopBeforeSources = (1UL << 2), // 即將開(kāi)始Source處理
kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進(jìn)入休眠
kCFRunLoopAfterWaiting = (1UL << 6), //從休眠狀態(tài)喚醒
kCFRunLoopExit = (1UL << 7), //退出RunLoop
kCFRunLoopAllActivities = 0x0FFFFFFFU //所有狀態(tài)
};

我們可以手動(dòng)創(chuàng)建一個(gè)CFRunLoopObserver來(lái)監(jiān)聽(tīng)Runloop的各種狀態(tài)

CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFStringRef runLoopMode = kCFRunLoopDefaultMode;
//參數(shù)1:構(gòu)造器
//參數(shù)2:監(jiān)聽(tīng)的CFRunLoopActivity(位移型枚舉)活動(dòng)狀態(tài),kCFRunLoopAllActivities代表所有狀態(tài)
//參數(shù)3:是否每次都需要監(jiān)聽(tīng)
//參數(shù)4:優(yōu)先級(jí)
//參數(shù)5:回調(diào)函數(shù)
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

switch (activity) {
case kCFRunLoopEntry:
NSLog(@"即將進(jìn)入 RunLoop");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"即將處理 Timer");
break;
case kCFRunLoopBeforeSources:
NSLog(@"即將處理 Source");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"即將進(jìn)入休眠");
;
break;
case kCFRunLoopAfterWaiting:
NSLog(@"從休眠中喚醒");
break;
case kCFRunLoopExit:
NSLog(@"即將退出Loop");
break;
default:
break;
}
});
//添加observer到runloop對(duì)象,來(lái)監(jiān)聽(tīng)指定的Mode
CFRunLoopAddObserver(runLoop, observer, runLoopMode);
CFRelease(observer);

我們經(jīng)扯腿可以在調(diào)用堆棧看到以下函數(shù)

//Observer回調(diào)
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__();
//CFRunLoopPerformBlock回調(diào)
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__();
//dispatch_getMain
static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__();
//timer,NSTimer...
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__();
//source0比如點(diǎn)擊事件
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__();
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__();
{
/// 1. 通知Observers录煤,即將進(jìn)入RunLoop
/// 此處有Observer會(huì)創(chuàng)建AutoreleasePool: _objc_autoreleasePoolPush();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopEntry);
do {

/// 2. 通知 Observers: 即將觸發(fā) Timer 回調(diào)鳄厌。
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeTimers);
/// 3. 通知 Observers: 即將觸發(fā) Source (非基于port的,Source0) 回調(diào)。
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);

/// 4. 觸發(fā) Source0 (非基于port的) 回調(diào)辐赞。
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);

/// 6. 通知Observers部翘,即將進(jìn)入休眠
/// 此處有Observer釋放并新建AutoreleasePool: _objc_autoreleasePoolPop(); _objc_autoreleasePoolPush();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeWaiting);

/// 7. sleep to wait msg.
mach_msg() -> mach_msg_trap();


/// 8. 通知Observers,線程被喚醒
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopAfterWaiting);

/// 9. 如果是被Timer喚醒的响委,回調(diào)Timer
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(timer);

/// 9. 如果是被dispatch喚醒的新思,執(zhí)行所有調(diào)用 dispatch_async 等方法放入main queue 的 block
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(dispatched_block);

/// 9. 如果如果Runloop是被 Source1 (基于port的) 的事件喚醒了,處理這個(gè)事件
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(source1);


} while (...);

/// 10. 通知Observers赘风,即將退出RunLoop
/// 此處有Observer釋放AutoreleasePool: _objc_autoreleasePoolPop();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopExit);
}

CFRunLoopRun

kenshincui

ibireme
/// 用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);
/// 執(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);
}

參考:
https://blog.ibireme.com/2015/05/18/runloop/
https://www.cnblogs.com/kenshincui/p/6823841.html
http://honglu.me/2017/03/30/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3RunLoop/
http://www.imlifengfeng.com/blog/?p=487

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末牍汹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子柬泽,更是在濱河造成了極大的恐慌慎菲,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锨并,死亡現(xiàn)場(chǎng)離奇詭異露该,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)第煮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)解幼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人包警,你說(shuō)我怎么就攤上這事撵摆。” “怎么了害晦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵特铝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我壹瘟,道長(zhǎng)鲫剿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任稻轨,我火速辦了婚禮灵莲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘澄者。我一直安慰自己笆呆,他們只是感情好请琳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著赠幕,像睡著了一般俄精。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榕堰,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天竖慧,我揣著相機(jī)與錄音,去河邊找鬼逆屡。 笑死圾旨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的魏蔗。 我是一名探鬼主播砍的,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼莺治!你這毒婦竟也來(lái)了廓鞠?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谣旁,失蹤者是張志新(化名)和其女友劉穎床佳,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體榄审,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砌们,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搁进。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浪感。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拷获,靈堂內(nèi)的尸體忽然破棺而出篮撑,到底是詐尸還是另有隱情,我是刑警寧澤匆瓜,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布赢笨,位于F島的核電站,受9級(jí)特大地震影響驮吱,放射性物質(zhì)發(fā)生泄漏茧妒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一左冬、第九天 我趴在偏房一處隱蔽的房頂上張望桐筏。 院中可真熱鬧,春花似錦拇砰、人聲如沸梅忌。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)牧氮。三九已至琼腔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間踱葛,已是汗流浹背丹莲。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尸诽,地道東北人甥材。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像性含,于是被迫代替她去往敵國(guó)和親洲赵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • 1 Runloop機(jī)制原理 深入理解RunLoop http://www.cocoachina.com/ios/2...
    Kevin_Junbaozi閱讀 4,011評(píng)論 4 30
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,438評(píng)論 0 13
  • RunLoop 的概念 一般來(lái)講商蕴,一個(gè)線程一次只能執(zhí)行一個(gè)任務(wù)板鬓,執(zhí)行完成后線程就會(huì)退出。如果我們需要一個(gè)機(jī)制究恤,讓線...
    Mirsiter_魏閱讀 618評(píng)論 0 2
  • 深入理解RunLoop 由ibireme| 2015-05-18 |iOS,技術(shù) RunLoop 是 iOS 和 ...
    橙娃閱讀 852評(píng)論 1 2
  • 突然很想用鉛筆在帶橫格的紙上寫(xiě)寫(xiě)東西,寫(xiě)的內(nèi)容無(wú)關(guān)緊要后德,寫(xiě)的字是否好看也不是重點(diǎn)部宿。重點(diǎn)是心中的東西很想傾訴出來(lái)——...
    玩笛子的古月子閱讀 203評(píng)論 0 1