GCD相關(guān)內(nèi)容

談到iOS多線程,一般都會談到四種方式:pthread、NSThread拷泽、GCD和NSOperation。其中袖瞻,蘋果推薦也是我們最經(jīng)常使用的無疑是GCD司致。對于身為開發(fā)者的我們來說,并發(fā)一直都很棘手聋迎,如果對GCD的理解不夠透徹脂矫,那么iOS開發(fā)的歷程絕對不會順利。這里霉晕,我會從幾個角度淺談我對GCD的理解庭再。

一、多線程背景

Although threads have been around for many years and continue to have their uses, they do not solve the general problem of executing multiple tasks in a scalable way. With threads, the burden of creating a scalable solution rests squarely on the shoulders of you, the developer. You have to decide how many threads to create and adjust that number dynamically as system conditions change. Another problem is that your application assumes most of the costs associated with creating and maintaining any threads it uses.

上述大致說出了直接操縱線程實(shí)現(xiàn)多線程的弊端:

開發(fā)人員必須根據(jù)系統(tǒng)的變化動態(tài)調(diào)整線程的數(shù)量和狀態(tài)牺堰,即對開發(fā)者的負(fù)擔(dān)重拄轻。

應(yīng)用程序會在創(chuàng)建和維護(hù)線程上消耗很多成本,即效率低伟葫。

相對的恨搓,GCD是一套低層級的C API,通過 GCD筏养,開發(fā)者只需要向隊(duì)列中添加一段代碼塊(block或C函數(shù)指針)斧抱,而不需要直接和線程打交道。GCD在后端管理著一個線程池渐溶,它不僅決定著你的代碼塊將在哪個線程被執(zhí)行辉浦,還根據(jù)可用的系統(tǒng)資源對這些線程進(jìn)行管理。GCD的工作方式茎辐,使其擁有很多優(yōu)點(diǎn)(快宪郊、穩(wěn)眉睹、準(zhǔn)):

快,更快的內(nèi)存效率废膘,因?yàn)榫€程棧不暫存于應(yīng)用內(nèi)存竹海。

穩(wěn),提供了自動的和全面的線程池管理機(jī)制丐黄,穩(wěn)定而便捷斋配。

準(zhǔn),提供了直接并且簡單的調(diào)用接口灌闺,使用方便艰争,準(zhǔn)確。

二桂对、隊(duì)列和任務(wù)

初學(xué)GCD的時候甩卓,肯定會糾結(jié)一些看似很關(guān)鍵但卻毫無意義的問題。比如:GCD和線程到底什么關(guān)系蕉斜;異步任務(wù)到底在哪個線程工作逾柿;隊(duì)列到底是個什么東西;mian queue和main thread到底搞什么名堂等等≌耍現(xiàn)在机错,這些我們直接略過(最后拾遺中會談一下),蘋果既然推薦使用GCD父腕,那么為什么還要糾結(jié)于線程呢弱匪?需要關(guān)注的只有兩個概念:隊(duì)列、任務(wù)璧亮。

1. 隊(duì)列

調(diào)度隊(duì)列是一個對象萧诫,它會以first-in、first-out的方式管理您提交的任務(wù)枝嘶。GCD有三種隊(duì)列類型:

串行隊(duì)列帘饶,串行隊(duì)列將任務(wù)以先進(jìn)先出(FIFO)的順序來執(zhí)行,所以串行隊(duì)列經(jīng)常用來做訪問某些特定資源的同步處理躬络。你可以也根據(jù)需要創(chuàng)建多個隊(duì)列尖奔,而這些隊(duì)列相對其他隊(duì)列都是并發(fā)執(zhí)行的。換句話說穷当,如果你創(chuàng)建了4個串行隊(duì)列提茁,每一個隊(duì)列在同一時間都只執(zhí)行一個任務(wù),對這四個任務(wù)來說馁菜,他們是相互獨(dú)立且并發(fā)執(zhí)行的茴扁。如果需要創(chuàng)建串行隊(duì)列,一般用dispatch_queue_create這個方法來實(shí)現(xiàn)汪疮,并指定隊(duì)列類型DISPATCH_QUEUE_SERIAL峭火。

并行隊(duì)列毁习,并發(fā)隊(duì)列雖然是能同時執(zhí)行多個任務(wù),但這些任務(wù)仍然是按照先到先執(zhí)行(FIFO)的順序來執(zhí)行的卖丸。并發(fā)隊(duì)列會基于系統(tǒng)負(fù)載來合適地選擇并發(fā)執(zhí)行這些任務(wù)纺且。并發(fā)隊(duì)列一般指的就是全局隊(duì)列(Global queue),進(jìn)程中存在四個全局隊(duì)列:高稍浆、中(默認(rèn))载碌、低、后臺四個優(yōu)先級隊(duì)列衅枫,可以調(diào)用dispatch_get_global_queue函數(shù)傳入優(yōu)先級來訪問隊(duì)列嫁艇。當(dāng)然我們也可以用dispatch_queue_create,并指定隊(duì)列類型DISPATCH_QUEUE_CONCURRENT弦撩,來自己創(chuàng)建一個并發(fā)隊(duì)列步咪。

主隊(duì)列,與主線程功能相同益楼。實(shí)際上猾漫,提交至main queue的任務(wù)會在主線程中執(zhí)行。main queue可以調(diào)用dispatch_get_main_queue()來獲得偏形。因?yàn)閙ain queue是與主線程相關(guān)的静袖,所以這是一個串行隊(duì)列。和其它串行隊(duì)列一樣俊扭,這個隊(duì)列中的任務(wù)一次只能執(zhí)行一個。它能保證所有的任務(wù)都在主線程執(zhí)行坠陈,而主線程是唯一可用于更新 UI 的線程萨惑。

額外說一句,上面也說過仇矾,隊(duì)列間的執(zhí)行是并行的庸蔼,但是也存在一些限制。比如贮匕,并行執(zhí)行的隊(duì)列數(shù)量受到內(nèi)核數(shù)的限制姐仅,無法真正做到大量隊(duì)列并行執(zhí)行;比如刻盐,對于并行隊(duì)列中的全局隊(duì)列而言掏膏,其存在優(yōu)先級關(guān)系,執(zhí)行的時候也會遵循其優(yōu)先順序敦锌,而不是并行馒疹。

2. 任務(wù)

linux內(nèi)核中的任務(wù)的定義是描述進(jìn)程的一種結(jié)構(gòu)體,而GCD中的任務(wù)只是一個代碼塊乙墙,它可以指一個block或者函數(shù)指針颖变。根據(jù)這個代碼塊添加進(jìn)入隊(duì)列的方式生均,將任務(wù)分為同步任務(wù)和異步任務(wù):

同步任務(wù),使用dispatch_sync將任務(wù)加入隊(duì)列腥刹。將同步任務(wù)加入串行隊(duì)列马胧,會順序執(zhí)行,一般不這樣做并且在一個任務(wù)未結(jié)束時調(diào)起其它同步任務(wù)會死鎖衔峰。將同步任務(wù)加入并行隊(duì)列佩脊,會順序執(zhí)行,但是也沒什么意義朽色。

異步任務(wù)邻吞,使用dispatch_async將任務(wù)加入隊(duì)列。將異步任務(wù)加入串行隊(duì)列葫男,會順序執(zhí)行抱冷,并且不會出現(xiàn)死鎖問題。將異步任務(wù)加入并行隊(duì)列梢褐,會并行執(zhí)行多個任務(wù)旺遮,這也是我們最常用的一種方式。

3. 簡單應(yīng)用

// 隊(duì)列的創(chuàng)建盈咳,queue1:中(默認(rèn))優(yōu)先級的全局并行隊(duì)列耿眉、queue2:主隊(duì)列、queue3:未指定type則為串行隊(duì)列鱼响、queue4:指定串行隊(duì)列鸣剪、queue5:指定并行隊(duì)列

dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_queue_t queue2 = dispatch_get_main_queue();

dispatch_queue_t queue3 = dispatch_queue_create("queue3", NULL);

dispatch_queue_t queue4 = dispatch_queue_create("queue4", DISPATCH_QUEUE_SERIAL);

dispatch_queue_t queue5 = dispatch_queue_create("queue5", DISPATCH_QUEUE_CONCURRENT);

// 隊(duì)列中添加異步任務(wù)

dispatch_async(queue1, ^{

// 任務(wù)

...

});

// 隊(duì)列中添加同步任務(wù)

dispatch_sync(queue1, ^{

// 任務(wù)

...

});

三、GCD常見用法和應(yīng)用場景

非常喜歡一句話:Talk is cheap, show me the code.接下來對GCD的使用丈积,我會通過代碼展示筐骇。

1. dispatch_async

一般用法

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(globalQueue, ^{

? ?// 一個異步的任務(wù),例如網(wǎng)絡(luò)請求江滨,耗時的文件操作等等

? ?...

? ?dispatch_async(dispatch_get_main_queue(), ^{

? ? ? ?// UI刷新

? ? ? ?...

? ?});

});

應(yīng)用場景

這種用法非常常見铛纬,比如開啟一個異步的網(wǎng)絡(luò)請求,待數(shù)據(jù)返回后返回主隊(duì)列刷新UI唬滑;又比如請求圖片告唆,待圖片返回刷新UI等等。

2. dispatch_after

一般用法

dispatch_queue_t queue= dispatch_get_main_queue();

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{

? ?// 在queue里面延遲執(zhí)行的一段代碼

? ?...

});

應(yīng)用場景

這為我們提供了一個簡單的延遲執(zhí)行的方式晶密,比如在view加載結(jié)束延遲執(zhí)行一個動畫等等擒悬。

3. dispatch_once

一般用法

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

? ?// 只執(zhí)行一次的任務(wù)

? ?...

});

應(yīng)用場景

可以使用其創(chuàng)建一個單例,也可以做一些其他只執(zhí)行一次的代碼惹挟,比如做一個只能點(diǎn)一次的button(好像沒啥用)茄螃。

4. dispatch_group

一般用法

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{

? ?// 異步任務(wù)1

});

dispatch_group_async(group, queue, ^{

? ?// 異步任務(wù)2

});

// 等待group中多個異步任務(wù)執(zhí)行完畢,做一些事情连锯,介紹兩種方式

// 方式1(不好归苍,會卡住當(dāng)前線程)

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

...

// 方式2(比較好)

dispatch_group_notify(group, mainQueue, ^{

? ?// 任務(wù)完成后用狱,在主隊(duì)列中做一些操作

? ?...

});

應(yīng)用場景

上述的一種方式,可以適用于自己維護(hù)的一些異步任務(wù)的同步問題拼弃;但是對于已經(jīng)封裝好的一些庫夏伊,比如AFNetworking等,我們不獲取其異步任務(wù)的隊(duì)列吻氧,這里可以通過一種計數(shù)的方式控制任務(wù)間同步溺忧,下面為解決單界面多接口的一種方式。

// 兩個請求和參數(shù)為我項(xiàng)目里面的不用在意盯孙。

// 計數(shù)+1

dispatch_group_enter(group);

[JDApiService getActivityDetailWithActivityId:self.activityId Location:stockAddressId SuccessBlock:^(NSDictionary *userInfo) {

? ?// 數(shù)據(jù)返回后一些處理

? ?...

? ?// 計數(shù)-1

? ?dispatch_group_leave(group);

} FailureBlock:^(NSError *error) {

? ?// 數(shù)據(jù)返回后一些處理

? ?...

? ?// 計數(shù)-1

? ?dispatch_group_leave(group);

}];

// 計數(shù)+1

dispatch_group_enter(group);

[JDApiService getAllCommentWithActivityId:self.activityId PageSize:3 PageNum:self.commentCurrentPage SuccessBlock:^(NSDictionary *userInfo) {

? ?// 數(shù)據(jù)返回后一些處理

? ?...

? ?// 計數(shù)-1

? ?dispatch_group_leave(group);

} FailureBlock:^(NSError *error) {

? ?// 數(shù)據(jù)返回后一些處理

? ?...

? ?// 計數(shù)-1

? ?dispatch_group_leave(group);

}];

// 其實(shí)用計數(shù)的說法可能不太對鲁森,但是就這么理解吧。會在計數(shù)為0的時候執(zhí)行dispatch_group_notify的任務(wù)振惰。

dispatch_group_notify(group, mainQueue, ^{

? ?// 一般為回主隊(duì)列刷新UI

? ?...

});

5. dispatch_barrier_async

一般用法

// dispatch_barrier_async的作用可以用一個詞概括--承上啟下歌溉,它保證此前的任務(wù)都先于自己執(zhí)行,此后的任務(wù)也遲于自己執(zhí)行骑晶。本例中痛垛,任務(wù)4會在任務(wù)1、2桶蛔、3都執(zhí)行完之后執(zhí)行匙头,而任務(wù)5、6會等待任務(wù)4執(zhí)行完后執(zhí)行仔雷。

dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{

? ?// 任務(wù)1

? ?...

});

dispatch_async(queue, ^{

? ?// 任務(wù)2

? ?...

});

dispatch_async(queue, ^{

? ?// 任務(wù)3

? ?...

});

dispatch_barrier_async(queue, ^{

? ?// 任務(wù)4

? ?...

});

dispatch_async(queue, ^{

? ?// 任務(wù)5

? ?...

});

dispatch_async(queue, ^{

? ?// 任務(wù)6

? ?...

});

應(yīng)用場景

和dispatch_group類似蹂析,dispatch_barrier也是異步任務(wù)間的一種同步方式,可以在比如文件的讀寫操作時使用碟婆,保證讀操作的準(zhǔn)確性识窿。另外,有一點(diǎn)需要注意脑融,dispatch_barrier_sync和dispatch_barrier_async只在自己創(chuàng)建的并發(fā)隊(duì)列上有效,在全局(Global)并發(fā)隊(duì)列缩宜、串行隊(duì)列上肘迎,效果跟dispatch_(a)sync效果一樣。

6. dispatch_apply

一般用法

// for循環(huán)做一些事情锻煌,輸出0123456789

for (int i = 0; i < 10; i ++) {

? ?NSLog(@"%d", i);

}

// dispatch_apply替換(當(dāng)且僅當(dāng)處理順序?qū)μ幚斫Y(jié)果無影響環(huán)境)妓布,輸出順序不定,比如1098673452

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

/*! dispatch_apply函數(shù)說明

*

* ?@brief ?dispatch_apply函數(shù)是dispatch_sync函數(shù)和Dispatch Group的關(guān)聯(lián)API

* ? ? ? ? 該函數(shù)按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中,并等到全部的處理執(zhí)行結(jié)束

*

* ?@param 10 ? ?指定重復(fù)次數(shù) ?指定10次

* ?@param queue 追加對象的Dispatch Queue

* ?@param index 帶有參數(shù)的Block, index的作用是為了按執(zhí)行的順序區(qū)分各個Block

*

*/

dispatch_apply(10, queue, ^(size_t index) {

? ?NSLog(@"%zu", index);

});

應(yīng)用場景

那么宋梧,dispatch_apply有什么用呢匣沼,因?yàn)閐ispatch_apply并行的運(yùn)行機(jī)制,效率一般快于for循環(huán)的類串行機(jī)制(在for一次循環(huán)中的處理任務(wù)很多時差距比較大)捂龄。比如這可以用來拉取網(wǎng)絡(luò)數(shù)據(jù)后提前算出各個控件的大小释涛,防止繪制時計算加叁,提高表單滑動流暢性,如果用for循環(huán)唇撬,耗時較多它匕,并且每個表單的數(shù)據(jù)沒有依賴關(guān)系,所以用dispatch_apply比較好窖认。

7. dispatch_suspend和dispatch_resume

一般用法

dispatch_queue_t queue = dispatch_get_main_queue();

dispatch_suspend(queue); //暫停隊(duì)列queue

dispatch_resume(queue); ?//恢復(fù)隊(duì)列queue

應(yīng)用場景

這種用法我還沒有嘗試過豫柬,不過其中有個需要注意的點(diǎn)。這兩個函數(shù)不會影響到隊(duì)列中已經(jīng)執(zhí)行的任務(wù)扑浸,隊(duì)列暫停后烧给,已經(jīng)添加到隊(duì)列中但還沒有執(zhí)行的任務(wù)不會執(zhí)行,直到隊(duì)列被恢復(fù)喝噪。

8. dispatch_semaphore_signal

一般用法

// dispatch_semaphore_signal有兩類用法:a础嫡、解決同步問題;b仙逻、解決有限資源訪問(資源為1驰吓,即互斥)問題。

// dispatch_semaphore_wait系奉,若semaphore計數(shù)為0則等待檬贰,大于0則使其減1。

// dispatch_semaphore_signal使semaphore計數(shù)加1缺亮。

// a翁涤、同步問題:輸出肯定為1、2萌踱、3葵礼。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_semaphore_t semaphore1 = dispatch_semaphore_create(1);

dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0);

dispatch_semaphore_t semaphore3 = dispatch_semaphore_create(0);

dispatch_async(queue, ^{

? ?// 任務(wù)1

? ?dispatch_semaphore_wait(semaphore1, DISPATCH_TIME_FOREVER);

? ?NSLog(@"1\n");

? ?dispatch_semaphore_signal(semaphore2);

? ?dispatch_semaphore_signal(semaphore1);

});

dispatch_async(queue, ^{

? ?// 任務(wù)2

? ?dispatch_semaphore_wait(semaphore2, DISPATCH_TIME_FOREVER);

? ?NSLog(@"2\n");

? ?dispatch_semaphore_signal(semaphore3);

? ?dispatch_semaphore_signal(semaphore2);

});

dispatch_async(queue, ^{

? ?// 任務(wù)3

? ?dispatch_semaphore_wait(semaphore3, DISPATCH_TIME_FOREVER);

? ?NSLog(@"3\n");

? ?dispatch_semaphore_signal(semaphore3);

});

// b、有限資源訪問問題:for循環(huán)看似能創(chuàng)建100個異步任務(wù)并鸵,實(shí)質(zhì)由于信號限制鸳粉,最多創(chuàng)建10個異步任務(wù)。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);

for (int i = 0; i

應(yīng)用場景

其實(shí)關(guān)于dispatch_semaphore_t园担,并沒有看到太多應(yīng)用和資料解釋届谈,我只能參照自己對linux信號量的理解寫了兩個用法,經(jīng)測試確實(shí)相似弯汰。這里艰山,就不對一些死鎖問題進(jìn)行討論了。

9. dispatch_set_context咏闪、dispatch_get_context和dispatch_set_finalizer_f

一般用法

// dispatch_set_context曙搬、dispatch_get_context是為了向隊(duì)列中傳遞上下文context服務(wù)的。

// dispatch_set_finalizer_f相當(dāng)于dispatch_object_t的析構(gòu)函數(shù)。

// 因?yàn)閏ontext的數(shù)據(jù)不是foundation對象纵装,所以arc不會自動回收征讲,一般在dispatch_set_finalizer_f中手動回收,所以一般講上述三個方法綁定使用搂擦。

- (void)test

{

// 幾種創(chuàng)建context的方式

// a稳诚、用C語言的malloc創(chuàng)建context數(shù)據(jù)。

// b瀑踢、用C++的new創(chuàng)建類對象扳还。

// c、用Objective-C的對象橱夭,但是要用__bridge等關(guān)鍵字轉(zhuǎn)為Core Foundation對象氨距。

dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);

if (queue) {

// "123"即為傳入的context

dispatch_set_context(queue, "123");

dispatch_set_finalizer_f(queue, &xigou);

}

dispatch_async(queue, ^{

char *string = dispatch_get_context(queue);

NSLog(@"%s", string);

});

}

// 該函數(shù)會在dispatch_object_t銷毀時調(diào)用。

void xigou(void *context)

{

// 釋放context的內(nèi)存(對應(yīng)上述abc)

// a棘劣、CFRelease(context);

// b俏让、free(context);

// c、delete context;

}

應(yīng)用場景

dispatch_set_context可以為隊(duì)列添加上下文數(shù)據(jù)茬暇,但是因?yàn)镚CD是C語言接口形式的首昔,所以其context參數(shù)類型是“void *”。需使用上述abc三種方式創(chuàng)建context糙俗,并且一般結(jié)合dispatch_set_finalizer_f使用勒奇,回收context內(nèi)存。

四巧骚、內(nèi)存和安全

稍微提一下吧赊颠,因?yàn)椴糠秩思m結(jié)于dispatch的內(nèi)存問題。

內(nèi)存

MRC:用dispatch_retain和dispatch_release管理dispatch_object_t內(nèi)存劈彪。

ARC:ARC在編譯時刻自動管理dispatch_object_t內(nèi)存竣蹦,使用retain和release會報錯。

安全

dispatch_queue是線程安全的沧奴,你可以隨意往里面添加任務(wù)痘括。

五、拾遺

這里主要提一下GCD的一些坑和線程的一些問題滔吠。

1. 死鎖

dispatch_sync

// 假設(shè)這段代碼執(zhí)行于主隊(duì)列

dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);

dispatch_queue_t mainQueue = dispatch_get_main_queue();

// 在主隊(duì)列添加同步任務(wù)

dispatch_sync(mainQueue, ^{

// 任務(wù)

...

});

// 在串行隊(duì)列添加同步任務(wù)

dispatch_sync(serialQueue, ^{

// 任務(wù)

...

dispatch_sync(serialQueue, ^{

// 任務(wù)

...

});

};

dispatch_apply

// 因?yàn)閐ispatch_apply會卡住當(dāng)前線程远寸,內(nèi)部的dispatch_apply會等待外部,外部的等待內(nèi)部屠凶,所以死鎖。

dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_apply(10, queue, ^(size_t) {

? ?// 任務(wù)

? ?...

? ?dispatch_apply(10, queue, ^(size_t) {

? ? ? ?// 任務(wù)

? ? ? ?...

? ?});

});

dispatch_barrier

dispatch_barrier_sync在串行隊(duì)列和全局并行隊(duì)列里面和dispatch_sync同樣的效果肆资,所以需考慮同dispatch_sync一樣的死鎖問題矗愧。

2. dispatch_time_t

// dispatch_time_t一般在dispatch_after和dispatch_group_wait等方法里作為參數(shù)使用。這里最需要注意的是一些宏的含義。

// NSEC_PER_SEC唉韭,每秒有多少納秒夜涕。

// USEC_PER_SEC,每秒有多少毫秒属愤。

// NSEC_PER_USEC女器,每毫秒有多少納秒。

// DISPATCH_TIME_NOW 從現(xiàn)在開始

// DISPATCH_TIME_FOREVE 永久

// time為1s的寫法

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);

六住诸、參考文獻(xiàn)

1驾胆、https://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW2

2、https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/

3贱呐、http://tutuge.me/2015/04/03/something-about-gcd/

4丧诺、http://www.reibang.com/p/85b75c7a6286

5、http://www.reibang.com/p/d56064507fb8

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奄薇,一起剝皮案震驚了整個濱河市驳阎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馁蒂,老刑警劉巖呵晚,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沫屡,居然都是意外死亡饵隙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門谁鳍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來癞季,“玉大人,你說我怎么就攤上這事倘潜”疗猓” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵涮因,是天一觀的道長废睦。 經(jīng)常有香客問我,道長养泡,這世上最難降的妖魔是什么嗜湃? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮澜掩,結(jié)果婚禮上购披,老公的妹妹穿的比我還像新娘。我一直安慰自己肩榕,他們只是感情好刚陡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般筐乳。 火紅的嫁衣襯著肌膚如雪歌殃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天蝙云,我揣著相機(jī)與錄音薪前,去河邊找鬼住拭。 笑死闯袒,一個胖子當(dāng)著我的面吹牛谒养,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朵你,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼各聘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了抡医?” 一聲冷哼從身側(cè)響起躲因,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忌傻,沒想到半個月后大脉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡水孩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年镰矿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俘种。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡秤标,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宙刘,到底是詐尸還是另有隱情苍姜,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布悬包,位于F島的核電站衙猪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏布近。R本人自食惡果不足惜垫释,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撑瞧。 院中可真熱鬧棵譬,春花似錦、人聲如沸预伺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至算谈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間料滥,已是汗流浹背然眼。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留葵腹,地道東北人高每。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像践宴,于是被迫代替她去往敵國和親鲸匿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

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

  • 簡介 GCD(Grand Central Dispatch)是在macOS10.6提出來的阻肩,后來在iOS4.0被引...
    sunmumu1222閱讀 850評論 0 2
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了带欢!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似烤惊。...
    Dely閱讀 9,226評論 21 42
  • 最近頗花了一番功夫把多線程GCD人的一些用法總結(jié)出來乔煞,一來幫自己鞏固一下知識、二來希望能幫到對這一塊還迷茫...
    人活一世閱讀 279評論 1 1
  • 文/寒霜 【原創(chuàng)】 主題:詠雨 體裁:詞牌《青玉案》 要求:以詩詞吾愛賀鑄版本為參考格式柒室。押韻限用新韻十唐仄或正韻...
    劉寒霜閱讀 1,084評論 3 9
  • 戴凱之歌 詞/張長青 握住我的手渡贾,握住你的手, 再遠(yuǎn)距離從此不再有雄右。 你用你的渴望空骚,我用我的赤誠, 美好未來從此一...
    凹丁閱讀 118評論 0 0