iOS之Run Loop詳解(轉(zhuǎn)載)

前言

不知道大家有沒(méi)有想過(guò)這個(gè)問(wèn)題栈暇,一個(gè)應(yīng)用開(kāi)始運(yùn)行以后放在那里脾猛,如果不對(duì)它進(jìn)行任何操作,這個(gè)應(yīng)用就像靜止了一樣贤姆,不會(huì)自發(fā)的有任何動(dòng)作發(fā)生榆苞,但是如果我們點(diǎn)擊界面上的一個(gè)按鈕,這個(gè)時(shí)候就會(huì)有對(duì)應(yīng)的按鈕響應(yīng)事件發(fā)生霞捡。給我們的感覺(jué)就像應(yīng)用一直處于隨時(shí)待命的狀態(tài)坐漏,在沒(méi)人操作的時(shí)候它一直在休息,在讓它干活的時(shí)候,它就能立刻響應(yīng)赊琳。其實(shí)街夭,這就是run loop的功勞。

一躏筏、線程與run loop

1.1 線程任務(wù)的類型

再來(lái)說(shuō)說(shuō)線程板丽。有些線程執(zhí)行的任務(wù)是一條直線,起點(diǎn)到終點(diǎn)趁尼;而另一些線程要干的活則是一個(gè)圓埃碱,不斷循環(huán),直到通過(guò)某種方式將它終止弱卡。直線線程如簡(jiǎn)單的Hello World乃正,運(yùn)行打印完,它的生命周期便結(jié)束了,像曇花一現(xiàn)那樣婶博;圓類型的如操作系統(tǒng)瓮具,一直運(yùn)行直到你關(guān)機(jī)。在IOS中凡人,圓型的線程就是通過(guò)run loop不停的循環(huán)實(shí)現(xiàn)的名党。

1.2 線程與run loop的關(guān)系

Run loop,正如其名挠轴,loop表示某種循環(huán)传睹,和run放在一起就表示一直在運(yùn)行著的循環(huán)。實(shí)際上岸晦,run loop和線程是緊密相連的欧啤,可以這樣說(shuō)run loop是為了線程而生,沒(méi)有線程启上,它就沒(méi)有存在的必要邢隧。Run loops是線程的基礎(chǔ)架構(gòu)部分,Cocoa和CoreFundation都提供了run loop對(duì)象方便配置和管理線程的run loop(以下都已Cocoa為例)冈在。每個(gè)線程倒慧,包括程序的主線程(main thread)都有與之相應(yīng)的run loop對(duì)象。

1.2.1 主線程的run loop默認(rèn)是啟動(dòng)的包券。

iOS的應(yīng)用程序里面纫谅,程序啟動(dòng)后會(huì)有一個(gè)如下的main()函數(shù):

int main(int argc,char *argv[]) {
    @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([appDelegate class]));
   }
}

重點(diǎn)是UIApplicationMain()函數(shù),這個(gè)方法會(huì)為main thread設(shè)置一個(gè)NSRunLoop對(duì)象溅固,這就解釋了本文開(kāi)始說(shuō)的為什么我們的應(yīng)用可以在無(wú)人操作的時(shí)候休息付秕,需要讓它干活的時(shí)候又能立馬響應(yīng)。

1.2.2 對(duì)其它線程來(lái)說(shuō)侍郭,run loop默認(rèn)是沒(méi)有啟動(dòng)的

對(duì)其它線程來(lái)說(shuō)盹牧,run loop默認(rèn)是沒(méi)有啟動(dòng)的俩垃,如果你需要更多的線程交互則可以手動(dòng)配置和啟動(dòng)励幼,如果線程只是去執(zhí)行一個(gè)長(zhǎng)時(shí)間的已確定的任務(wù)則不需要汰寓。

1.2.3 獲取線程的run loop

在任何一個(gè)Cocoa程序的線程中,都可以通過(guò):

NSRunLoop   *runloop = [NSRunLoopcurrentRunLoop];

來(lái)獲取到當(dāng)前線程的run loop苹粟。

1.3 關(guān)于run loop的幾點(diǎn)說(shuō)明

1.3.1 Cocoa中的NSRunLoop類并不是線程安全的

我們不能再一個(gè)線程中去操作另外一個(gè)線程的run loop對(duì)象有滑,那很可能會(huì)造成意想不到的后果。不過(guò)幸運(yùn)的是CoreFundation中的不透明類CFRunLoopRef是線程安全的嵌削,而且兩種類型的run loop完全可以混合使用毛好。Cocoa中的NSRunLoop類可以通過(guò)實(shí)例方法:

- (CFRunLoopRef)getCFRunLoop;

獲取對(duì)應(yīng)的CFRunLoopRef類,來(lái)達(dá)到線程安全的目的苛秕。

1.3.2 Run loop的管理并不完全是自動(dòng)的肌访。

我們?nèi)员仨氃O(shè)計(jì)線程代碼以在適當(dāng)?shù)臅r(shí)候啟動(dòng)run loop并正確響應(yīng)輸入事件,當(dāng)然前提是線程中需要用到run loop艇劫。而且吼驶,我們還需要使用while/for語(yǔ)句來(lái)驅(qū)動(dòng)run loop能夠循環(huán)運(yùn)行,下面的代碼就成功驅(qū)動(dòng)了一個(gè)run loop:

BOOL isRunning = NO;
do  {
    isRunning = [[NSRunLoopcurrentRunLoop] runMode:NSDefaultRunLoopModebeforeDate:[NSDatedistantFuture]];
} while (isRunning);

1.3.3 Run loop同時(shí)也負(fù)責(zé)autorelease pool的創(chuàng)建和釋放

在使用手動(dòng)的內(nèi)存管理方式的項(xiàng)目中店煞,會(huì)經(jīng)常用到很多自動(dòng)釋放的對(duì)象蟹演,如果這些對(duì)象不能夠被即時(shí)釋放掉,會(huì)造成內(nèi)存占用量急劇增大顷蟀。Run loop就為我們做了這樣的工作酒请,每當(dāng)一個(gè)運(yùn)行循環(huán)結(jié)束的時(shí)候,它都會(huì)釋放一次autorelease pool鸣个,同時(shí)pool中的所有自動(dòng)釋放類型變量都會(huì)被釋放掉羞反。

1.3.4 Run loop的優(yōu)點(diǎn)

一個(gè)run loop就是一個(gè)事件處理循環(huán),用來(lái)不停的監(jiān)聽(tīng)和處理輸入事件并將其分配到對(duì)應(yīng)的目標(biāo)上進(jìn)行處理囤萤。如果僅僅是想實(shí)現(xiàn)這個(gè)功能昼窗,你可能會(huì)想一個(gè)簡(jiǎn)單的while循環(huán)不就可以實(shí)現(xiàn)了嗎,用得著費(fèi)老大勁來(lái)做個(gè)那么復(fù)雜的機(jī)制阁将?顯然膏秫,蘋(píng)果的架構(gòu)設(shè)計(jì)師不是吃干飯的,你想到的他們?cè)缇拖脒^(guò)了做盅。
首先缤削,NSRunLoop是一種更加高明的消息處理模式,他就高明在對(duì)消息處理過(guò)程進(jìn)行了更好的抽象和封裝吹榴,這樣才能是的你不用處理一些很瑣碎很低層次的具體消息的處理亭敢,在NSRunLoop中每一個(gè)消息就被打包在input source或者是timer source(見(jiàn)后文)中了。
其次图筹,也是很重要的一點(diǎn)帅刀,使用run loop可以使你的線程在有工作的時(shí)候工作让腹,沒(méi)有工作的時(shí)候休眠,這可以大大節(jié)省系統(tǒng)資源扣溺。

二骇窍、Run loop相關(guān)知識(shí)點(diǎn)

2.1輸入事件來(lái)源

Run loop接收輸入事件來(lái)自兩種不同的來(lái)源:輸入源(input source)和定時(shí)源(timer source)。兩種源都使用程序的某一特定的處理例程來(lái)處理到達(dá)的事件锥余。圖-1顯示了run loop的概念結(jié)構(gòu)以及各種源腹纳。
需要說(shuō)明的是,當(dāng)你創(chuàng)建輸入源驱犹,你需要將其分配給run loop中的一個(gè)或多個(gè)模式(什么是模式嘲恍,下文將會(huì)講到)。模式只會(huì)在特定事件影響監(jiān)聽(tīng)的源雄驹。大多數(shù)情況下佃牛,run loop運(yùn)行在默認(rèn)模式下,但是你也可以使其運(yùn)行在自定義模式医舆。若某一源在當(dāng)前模式下不被監(jiān)聽(tīng)俘侠,那么任何其生成的消息只在run loop運(yùn)行在其關(guān)聯(lián)的模式下才會(huì)被傳遞。


Runloop的結(jié)構(gòu)和輸入源類型

2.1.1輸入源(input source)

傳遞異步事件彬向,通常消息來(lái)自于其他線程或程序兼贡。輸入源傳遞異步消息給相應(yīng)的處理例程,并調(diào)用runUntilDate:方法來(lái)退出(在線程里面相關(guān)的NSRunLoop對(duì)象調(diào)用)娃胆。

2.1.1.1基于端口的輸入源

基于端口的輸入源由內(nèi)核自動(dòng)發(fā)送遍希。
Cocoa和Core Foundation內(nèi)置支持使用端口相關(guān)的對(duì)象和函數(shù)來(lái)創(chuàng)建的基于端口的源。例如里烦,在Cocoa里面你從來(lái)不需要直接創(chuàng)建輸入源凿蒜。你只要簡(jiǎn)單的創(chuàng)建端口對(duì)象,并使用NSPort的方法把該端口添加到run loop胁黑。端口對(duì)象會(huì)自己處理創(chuàng)建和配置輸入源废封。
在Core Foundation,你必須人工創(chuàng)建端口和它的run loop源丧蘸。我們可以使用端口相關(guān)的函數(shù)(CFMachPortRef漂洋,CFMessagePortRef,CFSocketRef)來(lái)創(chuàng)建合適的對(duì)象力喷。下面的例子展示了如何創(chuàng)建一個(gè)基于端口的輸入源刽漂,將其添加到run loop并啟動(dòng):

voidcreatePortSource() {
    CFMessagePortRef port = CFMessagePortCreateLocal(kCFAllocatorDefault,CFSTR("com.someport"),myCallbackFunc, NULL,NULL);
 
    CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, port,0);
 
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source,kCFRunLoopCommonModes);
 
    while (pageStillLoading) {
        NSAutoreleasePool *pool = [[NSAutoreleasePoolalloc] init];
        CFRunLoopRun();
        [pool release];
    }
 
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source,kCFRunLoopDefaultMode);
 
    CFRelease(source);
}

2.1.1.2自定義輸入源

自定義的輸入源需要人工從其他線程發(fā)送。
為了創(chuàng)建自定義輸入源弟孟,必須使用Core Foundation里面的CFRunLoopSourceRef類型相關(guān)的函數(shù)來(lái)創(chuàng)建贝咙。你可以使用回調(diào)函數(shù)來(lái)配置自定義輸入源。Core Fundation會(huì)在配置源的不同地方調(diào)用回調(diào)函數(shù)拂募,處理輸入事件庭猩,在源從run loop移除的時(shí)候清理它窟她。
除了定義在事件到達(dá)時(shí)自定義輸入源的行為,你也必須定義消息傳遞機(jī)制蔼水。源的這部分運(yùn)行在單獨(dú)的線程里面震糖,并負(fù)責(zé)在數(shù)據(jù)等待處理的時(shí)候傳遞數(shù)據(jù)給源并通知它處理數(shù)據(jù)。消息傳遞機(jī)制的定義取決于你徙缴,但最好不要過(guò)于復(fù)雜试伙。創(chuàng)建并啟動(dòng)自定義輸入源的示例如下:

voidcreateCustomSource() {
    CFRunLoopSourceContext context = {0,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL};
 
    CFRunLoopSourceRef source =CFRunLoopSourceCreate(kCFAllocatorDefault,0, &context);
 
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source,kCFRunLoopDefaultMode);
 
    while (pageStillLoading) {
        NSAutoreleasePool *pool = [[NSAutoreleasePoolalloc] init];
        CFRunLoopRun();
        [pool release];
    }
 
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source,kCFRunLoopDefaultMode);
 
    CFRelease(source);
}

2.1.1.3 Cocoa上的Selector源

除了基于端口的源,Cocoa定義了自定義輸入源于样,允許你在任何線程執(zhí)行selector方法。和基于端口的源一樣潘靖,執(zhí)行selector請(qǐng)求會(huì)在目標(biāo)線程上序列化穿剖,減緩許多在線程上允許多個(gè)方法容易引起的同步問(wèn)題。不像基于端口的源卦溢,一個(gè)selector執(zhí)行完后會(huì)自動(dòng)從run loop里面移除糊余。
當(dāng)在其他線程上面執(zhí)行selector時(shí),目標(biāo)線程須有一個(gè)活動(dòng)的run loop单寂。對(duì)于你創(chuàng)建的線程贬芥,這意味著線程在你顯式的啟動(dòng)run loop之前是不會(huì)執(zhí)行selector方法的,而是一直處于休眠狀態(tài)宣决。
NSObject類提供了類似如下的selector方法:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)argwaitUntilDone:(BOOL)wait modes:(NSArray *)array;

2.1.2 定時(shí)源(timer source)

定時(shí)源在預(yù)設(shè)的時(shí)間點(diǎn)同步方式傳遞消息蘸劈,這些消息都會(huì)發(fā)生在特定時(shí)間或者重復(fù)的時(shí)間間隔。定時(shí)源則直接傳遞消息給處理例程尊沸,不會(huì)立即退出run loop威沫。
需要注意的是,盡管定時(shí)器可以產(chǎn)生基于時(shí)間的通知洼专,但它并不是實(shí)時(shí)機(jī)制棒掠。和輸入源一樣,定時(shí)器也和你的run loop的特定模式相關(guān)屁商。如果定時(shí)器所在的模式當(dāng)前未被run loop監(jiān)視烟很,那么定時(shí)器將不會(huì)開(kāi)始直到run loop運(yùn)行在相應(yīng)的模式下。類似的蜡镶,如果定時(shí)器在run loop處理某一事件期間開(kāi)始雾袱,定時(shí)器會(huì)一直等待直到下次run loop開(kāi)始相應(yīng)的處理程序。如果run loop不再運(yùn)行帽哑,那定時(shí)器也將永遠(yuǎn)不啟動(dòng)谜酒。
創(chuàng)建定時(shí)器源有兩種方法,
方法一:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:4.0
                                                  target:self
                                                selector:@selector(backgroundThreadFire:)
                                                userInfo:nil
                                                 repeats:YES];
 
[[NSRunLoop currentRunLoop] addTimer:timerforMode:NSDefaultRunLoopMode];

方法二:

[NSTimer scheduledTimerWithTimeInterval:10
                                 target:self
                               selector:@selector(backgroundThreadFire:)
                               userInfo:nil
                                repeats:YES];

2.2 RunLoop觀察者

源是在合適的同步或異步事件發(fā)生時(shí)觸發(fā)妻枕,而run loop觀察者則是在run loop本身運(yùn)行的特定時(shí)候觸發(fā)僻族。你可以使用run loop觀察者來(lái)為處理某一特定事件或是進(jìn)入休眠的線程做準(zhǔn)備粘驰。你可以將run loop觀察者和以下事件關(guān)聯(lián):
Runloop入口
Runloop何時(shí)處理一個(gè)定時(shí)器
Runloop何時(shí)處理一個(gè)輸入源
Runloop何時(shí)進(jìn)入睡眠狀態(tài)
Runloop何時(shí)被喚醒,但在喚醒之前要處理的事件
Runloop終止

和定時(shí)器類似述么,在創(chuàng)建的時(shí)候你可以指定run loop觀察者可以只用一次或循環(huán)使用蝌数。若只用一次,那么在它啟動(dòng)后度秘,會(huì)把它自己從run loop里面移除顶伞,而循環(huán)的觀察者則不會(huì)。定義觀察者并把它添加到run loop剑梳,只能使用Core Fundation唆貌。下面的例子演示了如何創(chuàng)建run loop的觀察者:

- (void)addObserverToCurrentRunloop {
    // The application uses garbage collection, so noautorelease pool is needed.
 
    NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop];
   // Create a run loop observer and attach it to the runloop.
 
    CFRunLoopObserverContext  context = {0,self, NULL,NULL, NULL};
   CFRunLoopObserverRef    observer =CFRunLoopObserverCreate(kCFAllocatorDefault,
 
                                                              kCFRunLoopBeforeTimers,YES, 0, &myRunLoopObserver, &context);
 
    if (observer) {
        CFRunLoopRef    cfLoop = [myRunLoopgetCFRunLoop];
       CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode);
    }
}

其中,kCFRunLoopBeforeTimers表示選擇監(jiān)聽(tīng)定時(shí)器觸發(fā)前處理事件垢乙,后面的YES表示循環(huán)監(jiān)聽(tīng)锨咙。

2.3 RunLoop的事件隊(duì)列

每次運(yùn)行run loop,你線程的run loop對(duì)會(huì)自動(dòng)處理之前未處理的消息追逮,并通知相關(guān)的觀察者酪刀。具體的順序如下:
通知觀察者run loop已經(jīng)啟動(dòng)
通知觀察者任何即將要開(kāi)始的定時(shí)器
通知觀察者任何即將啟動(dòng)的非基于端口的源
啟動(dòng)任何準(zhǔn)備好的非基于端口的源
如果基于端口的源準(zhǔn)備好并處于等待狀態(tài),立即啟動(dòng)钮孵;并進(jìn)入步驟9骂倘。
通知觀察者線程進(jìn)入休眠
將線程置于休眠直到任一下面的事件發(fā)生:某一事件到達(dá)基于端口的源
定時(shí)器啟動(dòng)
Run loop設(shè)置的時(shí)間已經(jīng)超時(shí)
run loop被顯式喚醒

通知觀察者線程將被喚醒。
處理未處理的事件如果用戶定義的定時(shí)器啟動(dòng)巴席,處理定時(shí)器事件并重啟run loop历涝。進(jìn)入步驟2
如果輸入源啟動(dòng),傳遞相應(yīng)的消息
如果run loop被顯式喚醒而且時(shí)間還沒(méi)超時(shí)情妖,重啟run loop睬关。進(jìn)入步驟2

通知觀察者run loop結(jié)束。

因?yàn)槎〞r(shí)器和輸入源的觀察者是在相應(yīng)的事件發(fā)生之前傳遞消息毡证,所以通知的時(shí)間和實(shí)際事件發(fā)生的時(shí)間之間可能存在誤差电爹。如果需要精確時(shí)間控制,你可以使用休眠和喚醒通知來(lái)幫助你校對(duì)實(shí)際發(fā)生事件的時(shí)間料睛。
因?yàn)楫?dāng)你運(yùn)行run loop時(shí)定時(shí)器和其它周期性事件經(jīng)常需要被傳遞丐箩,撤銷run loop也會(huì)終止消息傳遞。典型的例子就是鼠標(biāo)路徑追蹤恤煞。因?yàn)槟愕拇a直接獲取到消息而不是經(jīng)由程序傳遞屎勘,因此活躍的定時(shí)器不會(huì)開(kāi)始直到鼠標(biāo)追蹤結(jié)束并將控制權(quán)交給程序。
Run loop可以由run loop對(duì)象顯式喚醒居扒。其它消息也可以喚醒run loop概漱。例如,添加新的非基于端口的源會(huì)喚醒run loop從而可以立即處理輸入源而不需要等待其他事件發(fā)生后再處理喜喂。
從這個(gè)事件隊(duì)列中可以看出:
①如果是事件到達(dá)瓤摧,消息會(huì)被傳遞給相應(yīng)的處理程序來(lái)處理竿裂, runloop處理完當(dāng)次事件后,run loop會(huì)退出照弥,而不管之前預(yù)定的時(shí)間到了沒(méi)有腻异。你可以重新啟動(dòng)run loop來(lái)等待下一事件。
②如果線程中有需要處理的源这揣,但是響應(yīng)的事件沒(méi)有到來(lái)的時(shí)候悔常,線程就會(huì)休眠等待相應(yīng)事件的發(fā)生。這就是為什么run loop可以做到讓線程有工作的時(shí)候忙于工作给赞,而沒(méi)工作的時(shí)候處于休眠狀態(tài)机打。

2.4 什么時(shí)候使用run loop

僅當(dāng)在為你的程序創(chuàng)建輔助線程的時(shí)候,你才需要顯式運(yùn)行一個(gè)run loop塞俱。Run loop是程序主線程基礎(chǔ)設(shè)施的關(guān)鍵部分姐帚。所以,Cocoa和Carbon程序提供了代碼運(yùn)行主程序的循環(huán)并自動(dòng)啟動(dòng)run loop障涯。IOS程序中UIApplication的run方法(或Mac OS X中的NSApplication)作為程序啟動(dòng)步驟的一部分,它在程序正常啟動(dòng)的時(shí)候就會(huì)啟動(dòng)程序的主循環(huán)膳汪。類似的唯蝶,RunApplicationEventLoop函數(shù)為Carbon程序啟動(dòng)主循環(huán)。如果你使用xcode提供的模板創(chuàng)建你的程序遗嗽,那你永遠(yuǎn)不需要自己去顯式的調(diào)用這些例程粘我。
對(duì)于輔助線程,你需要判斷一個(gè)run loop是否是必須的痹换。如果是必須的征字,那么你要自己配置并啟動(dòng)它。你不需要在任何情況下都去啟動(dòng)一個(gè)線程的run loop娇豫。比如匙姜,你使用線程來(lái)處理一個(gè)預(yù)先定義的長(zhǎng)時(shí)間運(yùn)行的任務(wù)時(shí),你應(yīng)該避免啟動(dòng)run loop冯痢。Run loop在你要和線程有更多的交互時(shí)才需要氮昧,比如以下情況:
使用端口或自定義輸入源來(lái)和其他線程通信
使用線程的定時(shí)器
Cocoa中使用任何performSelector…的方法
使線程周期性工作

如果你決定在程序中使用run loop,那么它的配置和啟動(dòng)都很簡(jiǎn)單浦楣。和所有線程編程一樣袖肥,你需要計(jì)劃好在輔助線程退出線程的情形。讓線程自然退出往往比強(qiáng)制關(guān)閉它更好振劳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末椎组,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子历恐,更是在濱河造成了極大的恐慌寸癌,老刑警劉巖专筷,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異灵份,居然都是意外死亡仁堪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)填渠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)弦聂,“玉大人,你說(shuō)我怎么就攤上這事氛什≥汉” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵枪眉,是天一觀的道長(zhǎng)捺檬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贸铜,這世上最難降的妖魔是什么堡纬? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮蒿秦,結(jié)果婚禮上烤镐,老公的妹妹穿的比我還像新娘。我一直安慰自己棍鳖,他們只是感情好炮叶,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著渡处,像睡著了一般镜悉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上医瘫,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天侣肄,我揣著相機(jī)與錄音,去河邊找鬼登下。 笑死茫孔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的被芳。 我是一名探鬼主播缰贝,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼畔濒!你這毒婦竟也來(lái)了剩晴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赞弥,沒(méi)想到半個(gè)月后毅整,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绽左,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年悼嫉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拼窥。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡戏蔑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鲁纠,到底是詐尸還是另有隱情总棵,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布改含,位于F島的核電站情龄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捍壤。R本人自食惡果不足惜骤视,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鹃觉。 院中可真熱鬧尚胞,春花似錦、人聲如沸帜慢。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)粱玲。三九已至,卻和暖如春拜轨,著一層夾襖步出監(jiān)牢的瞬間抽减,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工橄碾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卵沉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓法牲,卻偏偏與公主長(zhǎng)得像史汗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拒垃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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

  • 由于文章長(zhǎng)度限制停撞,本文作為[譯]線程編程指南(一)后續(xù)部分。 Run Loops Run loop是與線程相關(guān)的基...
    巧巧的二表哥閱讀 1,191評(píng)論 0 5
  • 這是一篇對(duì)Run Loop開(kāi)發(fā)文檔《Threading Program Guide:Run Loops》的翻譯,來(lái)...
    鴻雁長(zhǎng)飛光不度閱讀 3,649評(píng)論 3 29
  • 從事iOS編程1年戈毒,一直沒(méi)搞懂RunLoop原理艰猬,不知道大家有沒(méi)有想過(guò)這個(gè)問(wèn)題,一個(gè)應(yīng)用開(kāi)始運(yùn)行以后放在那...
    DeerRun閱讀 889評(píng)論 0 8
  • 做了一年多的IOS開(kāi)發(fā)埋市,對(duì)IOS和Objective-C深層次的了解還十分有限冠桃,大多還停留在會(huì)用API的級(jí)別,這是...
    韓七夏閱讀 296評(píng)論 0 0
  • 一個(gè)月后道宅,少年軍團(tuán)的所有成員都放暑假了食听。夏小火因?yàn)榭荚嚦煽?jī)比較優(yōu)秀,所以開(kāi)心的請(qǐng)杰克斯和苗陳新去“夏夜茉莉”奶...
    夏小伙閱讀 450評(píng)論 0 5