Swift4 - GCD的使用

從Swift3開始GCD的API就發(fā)生了很大的變化详拙,更加簡(jiǎn)潔嘹朗,使用起來(lái)更方便。像我們經(jīng)常開啟一個(gè)異步線程處理事情然后切回主線程刷新UI操作诗祸,這里就變的非常簡(jiǎn)單了跑芳。

? ? DispatchQueue.global().async {

? ? ? ? // do async task

? ? ? ? DispatchQueue.main.async {

? ? ? ? ? ? // update UI

? ? ? ? ? }

? ? ? }

DispatchQueue

DispatchQueue字面意思就是派發(fā)列隊(duì),主要是管理需要執(zhí)行的任務(wù)直颅,任務(wù)以閉包或者DispatchWorkItem的方式進(jìn)行提交.列隊(duì)中的任務(wù)遵守FIFO原則博个。如果對(duì)于列隊(duì)不是很了解,可以看這里际乘。 列隊(duì)可以是串行也可以是并發(fā)坡倔,串行列隊(duì)按順序執(zhí)行,并發(fā)列隊(duì)會(huì)并發(fā)執(zhí)行任務(wù)脖含,但是我們并不知道具體任務(wù)的執(zhí)行順序罪塔。

列隊(duì)的分類

系統(tǒng)列隊(duì)

主列隊(duì)

let mainQueue = DispatchQueue.main

全局列隊(duì)

let globalQueue = DispatchQueue.global()

用戶創(chuàng)建列隊(duì)

創(chuàng)建自己的列隊(duì),簡(jiǎn)單的方式就是指定列隊(duì)的名稱即可

let queue = DispatchQueue(label: "com.conpanyName.queue")

這樣的初始化的列隊(duì)有著默認(rèn)的配置項(xiàng),默認(rèn)的列隊(duì)是串行列隊(duì)养葵。便捷構(gòu)造函數(shù)如下

public convenience init(label: String, qos: DispatchQoS = default, attributes: DispatchQueue.Attributes = default, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = default, target: DispatchQueue? = default)

我們也可以自己顯示設(shè)置相關(guān)屬性征堪,創(chuàng)建一個(gè)并發(fā)列隊(duì)

? ? let label = "com.conpanyName.queue"

? ? let qos = DispatchQoS.default

? ? let attributes = DispatchQueue.Attributes.concurrent

? ? let autoreleaseFrequnecy = DispatchQueue.AutoreleaseFrequency.never

? ? let queue = DispatchQueue(label: label, qos: qos, attributes: attributes, autoreleaseFrequency: autoreleaseFrequnecy, target: nil)

參數(shù)介紹

label:列隊(duì)的標(biāo)識(shí)符,能夠方便區(qū)分列隊(duì)進(jìn)行調(diào)試

qos:列隊(duì)的優(yōu)先級(jí)(quality of service)关拒,其值如下:

? ? ? public struct DispatchQoS : Equatable {

? ? ? ? ? ? public static let background: DispatchQoS

? ? ? ? ? ? public static let utility: DispatchQoS

? ? ? ? ? ? public static let `default`: DispatchQoS

? ? ? ? ? ? public static let userInitiated: DispatchQoS

? ? ? ? ? ? public static let userInteractive: DispatchQoS

? ? ? ? ? ? public static let unspecified: DispatchQoS

? ? ? }

優(yōu)先級(jí)由最低的background到最高的userInteractive共五個(gè)佃蚜,還有一個(gè)為定義的unspecified.

background:最低優(yōu)先級(jí),等同于DISPATCH_QUEUE_PRIORITY_BACKGROUND. 用戶不可見着绊,比如:在后臺(tái)存儲(chǔ)大量數(shù)據(jù)

utility:優(yōu)先級(jí)等同于DISPATCH_QUEUE_PRIORITY_LOW谐算,可以執(zhí)行很長(zhǎng)時(shí)間,再通知用戶結(jié)果归露。比如:下載一個(gè)大文件洲脂,網(wǎng)絡(luò),計(jì)算

default:默認(rèn)優(yōu)先級(jí),優(yōu)先級(jí)等同于DISPATCH_QUEUE_PRIORITY_DEFAULT剧包,建議大多數(shù)情況下使用默認(rèn)優(yōu)先級(jí)

userInitiated:優(yōu)先級(jí)等同于DISPATCH_QUEUE_PRIORITY_HIGH,需要立刻的結(jié)果

.userInteractive:用戶交互相關(guān)恐锦,為了好的用戶體驗(yàn),任務(wù)需要立馬執(zhí)行疆液。使用該優(yōu)先級(jí)用于UI更新一铅,事件處理和小工作量任務(wù),在主線程執(zhí)行堕油。

Qos指定了列隊(duì)工作的優(yōu)先級(jí)潘飘,系統(tǒng)會(huì)根據(jù)優(yōu)先級(jí)來(lái)調(diào)度工作,越高的優(yōu)先級(jí)能夠越快被執(zhí)行掉缺,但是也會(huì)消耗功能福也,所以準(zhǔn)確的指定優(yōu)先級(jí)能夠保證app有效的使用資源。詳細(xì)可以看這里

attributes:列隊(duì)的屬性攀圈,也可以說(shuō)是類型暴凑,即是并發(fā)還是串行。attributes是一個(gè)結(jié)構(gòu)體并遵守OptionSet協(xié)議赘来,所以傳入的參數(shù)可以為[.option1, .option2]

? ? public struct Attributes : OptionSet {

? ? ? ? ? public let rawValue: UInt64

? ? ? ? ? public init(rawValue: UInt64)

? ? ? ? ? public static let concurrent: DispatchQueue.Attributes

? ? ? ? ? public static let initiallyInactive: DispatchQueue.Attributes

? ? }

默認(rèn):列隊(duì)是串行的

.concurrent:列隊(duì)是并發(fā)的

.initiallyInactive:列隊(duì)不會(huì)自動(dòng)執(zhí)行现喳,需要開發(fā)中手動(dòng)觸發(fā)

autoreleaseFrequency:自動(dòng)釋放頻率凯傲,有些列隊(duì)會(huì)在執(zhí)行完任務(wù)之后自動(dòng)釋放,有些是不會(huì)自動(dòng)釋放的嗦篱,需要手動(dòng)釋放冰单。

簡(jiǎn)單看一下列隊(duì)優(yōu)先級(jí)

? ? DispatchQueue.global(qos: .background).async {

? ? ? ? for i in 1...5 {

? ? ? ? ? ? print("background: \(i)")

? ? ? ? }

? ? }

? ? DispatchQueue.global(qos: .default).async {

? ? ? ? for i in 1...5 {

? ? ? ? ? ? print("default: \(i)")

? ? ? ? }

? ? }

? ? DispatchQueue.global(qos: .userInteractive).async {

? ? ? ? for i in 1...5 {

? ? ? ? ? ? print("userInteractive: \(i)")

? ? ? ? }

? ? }

? ? 執(zhí)行結(jié)果:

? ? ? ? ? ? default: 1

? ? ? ? ? ? userInteractive: 1

? ? ? ? ? ? background: 1

? ? ? ? ? ? default: 2

? ? ? ? ? ? userInteractive: 2

? ? ? ? ? ? background: 2

? ? ? ? ? ? userInteractive: 3

? ? ? ? ? ? default: 3

? ? ? ? ? ? userInteractive: 4

? ? ? ? ? ? userInteractive: 5

? ? ? ? ? ? default: 4

? ? ? ? ? ? background: 3

? ? ? ? ? ? default: 5

? ? ? ? ? ? background: 4

? ? ? ? ? ? background: 5

DispatchWorkItem

DispatchWorkItem是用于幫助DispatchQueue來(lái)執(zhí)行列隊(duì)中的任務(wù)。類的相關(guān)內(nèi)容如下:

? ? public class DispatchWorkItem {

? ? ? ? ? public init(qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, block: @escaping @convention(block) () -> Swift.Void)

? ? ? ? ? public func perform()

? ? ? ? ? public func wait()

? ? ? ? ? public func wait(timeout: DispatchTime) -> DispatchTimeoutResult

? ? ? ? ? public func wait(wallTimeout: DispatchWallTime) -> DispatchTimeoutResult

? ? ? ? ? public func notify(qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, queue: DispatchQueue, execute: @escaping @convention(block) () -> Swift.Void)

? ? ? ? ? public func notify(queue: DispatchQueue, execute: DispatchWorkItem)

? ? ? ? ? public func cancel()

? ? ? ? ? public var isCancelled: Bool { get }

? ? }

一般情況下灸促,我們開啟一個(gè)異步線程诫欠,會(huì)這樣創(chuàng)建列隊(duì)并執(zhí)行async方法,以閉包的方式提交任務(wù)浴栽。

? ? DispatchQueue.global().async {

? ? ? ? // do async task

? ? }

但是Swift3中使用了DispatchWorkItem類將任務(wù)封裝成為對(duì)象荒叼,由對(duì)象進(jìn)行任務(wù)。

? ? let item = DispatchWorkItem {

? ? ? ? ? // do task

? ? }

? ? DispatchQueue.global().async(execute: item)

當(dāng)然典鸡,這里也可以使用DispatchWorkItem實(shí)例對(duì)象的perform方法執(zhí)行任務(wù)

? ? let workItem = DispatchWorkItem {

? ? ? ? // do task

? ? }

? ? DispatchQueue.global().async {

? ? ? ? workItem.perform()

? ? }

但是對(duì)比一下兩種方式被廓,顯然第一種更加簡(jiǎn)潔,方便萝玷。

執(zhí)行任務(wù)結(jié)束通過(guò)nofify獲得通知

? ? let workItem = DispatchWorkItem {

? ? ? ? // do async task

? ? ? ? print(Thread.current)

? ? }


? ? DispatchQueue.global().async {

? ? ? ? workItem.perform()

? ? }


? ? workItem.notify(queue: DispatchQueue.main) {

? ? ? ? // update UI

? ? ? ? print(Thread.current)

? ? }

使用wait等待任務(wù)執(zhí)行完成

? ? let queue = DispatchQueue(label: "queue", attributes: .concurrent)

? ? let workItem = DispatchWorkItem {

? ? ? ? sleep(5)

? ? ? ? print("done")

? ? }


? ? queue.async(execute: workItem)

? ? print("before waiting")

? ? workItem.wait()

? ? print("after waiting")


? ? 執(zhí)行結(jié)果:

? ? ? ? ? ? before waiting

? ? ? ? ? ? done

? ? ? ? ? ? after waiting

也可以在初始化的時(shí)候指定更多的參數(shù)

? ? let item = DispatchWorkItem(qos: .default, flags: .barrier) {

? ? ? ? // do task

? ? }

第一個(gè)參數(shù)同樣說(shuō)優(yōu)先級(jí)嫁乘,第二個(gè)參數(shù)指定flag

? ? public struct DispatchWorkItemFlags : OptionSet, RawRepresentable {

? ? ? ? public let rawValue: UInt

? ? ? ? public init(rawValue: UInt)

? ? ? ? public static let barrier: DispatchWorkItemFlags

? ? ? ? public static let detached: DispatchWorkItemFlags

? ? ? ? public static let assignCurrentContext: DispatchWorkItemFlags

? ? ? ? public static let noQoS: DispatchWorkItemFlags

? ? ? ? public static let inheritQoS: DispatchWorkItemFlags

? ? ? ? public static let enforceQoS: DispatchWorkItemFlags

? ? }

barrier

假如我們有一個(gè)并發(fā)的列隊(duì)用來(lái)讀寫一個(gè)數(shù)據(jù)對(duì)象,如果這個(gè)列隊(duì)的操作是讀球碉,那么可以同時(shí)多個(gè)進(jìn)行蜓斧。如果有寫的操作,則必須保證在執(zhí)行寫操作時(shí)睁冬,不會(huì)有讀取的操作執(zhí)行法精,必須等待寫操作完成之后再開始讀取操作,否則會(huì)造成讀取的數(shù)據(jù)出錯(cuò)痴突,經(jīng)典的讀寫問(wèn)題。這里我們就可以使用barrier:

? ? let item = DispatchWorkItem(qos: .default, flags: .barrier) {

? ? ? ? // write data

? ? }

? ? let dataQueue = DispatchQueue(label: "com.data.queue", attributes: .concurrent)

? ? dataQueue.async(execute: item)

字典的讀寫操作

? ? private let concurrentQueue = DispatchQueue(label: "concurrentQueue", attributes: .concurrent)

? ? private var dictionary: [String: Any] = [:]


? ? public func set(_ value: Any?, forKey key: String) {

? ? ? ? // .barrier flag ensures that within the queue all reading is done

? ? ? ? // before the below writing is performed and

? ? ? ? // pending readings start after below writing is performed

? ? ? ? concurrentQueue.async(flags: .barrier) {

? ? ? ? ? ? ? self.dictionary[key] = value

? ? ? ? }

? ? }


? ? public func object(forKey key: String) -> Any? {

? ? ? ? var result: Any?

? ? ? ? concurrentQueue.sync {

? ? ? ? ? ? result = dictionary[key]

? ? ? ? }


? ? ? ? // returns after concurrentQueue is finished operation

? ? ? ? // beacuse concurrentQueue is run synchronously

? ? ? ? return result

? ? }

通過(guò)在并發(fā)代碼中使用barrier將能夠保證寫操作在所有讀取操作完成之后進(jìn)行狼荞,而且確保寫操作執(zhí)行完成之后再開始后續(xù)的讀取操作辽装。具體的詳情看這里

延時(shí)處理

使用asyncAfter來(lái)提交任務(wù)進(jìn)行延遲。之前是使用dispatch_time,現(xiàn)在是使用DispatchTime對(duì)象表示相味∈盎可以使用靜態(tài)方法now獲得當(dāng)前時(shí)間,然后再通過(guò)加上DispatchTimeInterval枚舉獲得一個(gè)需要延遲的時(shí)間丰涉。注意:僅僅是用于在具體時(shí)間執(zhí)行任務(wù)拓巧,不要在資源競(jìng)爭(zhēng)的情況下使用。并且在主列隊(duì)使用一死。

? ? let delay = DispatchTime.now() + DispatchTimeInterval.seconds(10)

? ? DispatchQueue.main.asyncAfter(deadline: delay) {

? ? ? ? // 延遲執(zhí)行

? ? }

我們可以進(jìn)一步簡(jiǎn)化肛度,直接添加時(shí)間

? ? let delay = DispatchTime.now() + 10

? ? DispatchQueue.main.asyncAfter(deadline: delay) {

? ? ? ? // 延遲執(zhí)行

? ? }

因?yàn)樵贒ispatchTime中自定義了“+”號(hào)。

public func +(time: DispatchTime, seconds: Double) -> DispatchTime

更多有關(guān)延時(shí)操作看這里

DispatchGroup

DispatchGroup用于管理一組任務(wù)的執(zhí)行投慈,然后監(jiān)聽任務(wù)的完成承耿,進(jìn)而執(zhí)行后續(xù)操作冠骄。比如:同一個(gè)頁(yè)面發(fā)送多個(gè)網(wǎng)絡(luò)請(qǐng)求,等待所有結(jié)果請(qǐng)求成功刷新UI界面加袋。一般的操作如下:

? ? let queue = DispatchQueue.global()

? ? let group = DispatchGroup()


? ? queue.async(group: group) {

? ? ? ? print("Task one finished")

? ? }

? ? queue.async(group: group) {

? ? ? ? print("Task two finished")

? ? }

? ? queue.async(group: group) {

? ? ? ? print("Task three finished")

? ? }

? ? group.notify(queue: queue) {

? ? ? ? print("All task has finished")

? ? }

打印如下:

Task three finished

Task two finished

Task one finished

All task has finished

由于是并發(fā)執(zhí)行異步任務(wù)凛辣,所以任務(wù)的先后次序是不一定的,看起來(lái)符合我們的需求职烧,最后接受通知然后可以刷新UI操作扁誓。但是真實(shí)的網(wǎng)絡(luò)請(qǐng)求是異步、耗時(shí)的蚀之,并不是立馬就返回蝗敢,所以我們使用asyncAfter模擬延時(shí)看看,將任務(wù)1延時(shí)一秒執(zhí)行:

? ? let queue = DispatchQueue.global()

? ? let group = DispatchGroup()


? ? queue.async(group: group) {

? ? ? ? DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {

? ? ? ? ? ? print("Task one finished")

? ? ? ? })

? ? }

? ? queue.async(group: group) {

? ? ? ? print("Task two finished")

? ? }

? ? queue.async(group: group) {

? ? ? ? print("Task three finished")

? ? }

? ? group.notify(queue: queue) {

? ? ? ? print("All task has finished")

? ? }

結(jié)果卻不是我們預(yù)期的那樣恬总,輸出結(jié)果如下:

Task two finished

Task three finished

All task has finished

Task one finished

所以前普,為了真正實(shí)現(xiàn)預(yù)期的效果,我們需要配合group的enter和leave兩個(gè)函數(shù)壹堰。每次執(zhí)行g(shù)roup.enter()表示一個(gè)任務(wù)被加入到列隊(duì)組group中拭卿,此時(shí)group中的任務(wù)的引用計(jì)數(shù)會(huì)加1,當(dāng)使用group.leave() 贱纠,表示group中的一個(gè)任務(wù)完成峻厚,group中任務(wù)的引用計(jì)數(shù)減1.當(dāng)group列隊(duì)組里面的任務(wù)引用計(jì)數(shù)為0時(shí),會(huì)通知notify函數(shù)谆焊,任務(wù)執(zhí)行完成惠桃。注意:enter()和leave()成對(duì)出現(xiàn)的。

? ? ? let queue = DispatchQueue.global()

? ? ? let group = DispatchGroup()


? ? ? group.enter()

? ? ? queue.async(group: group) {

? ? ? ? ? DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {

? ? ? ? ? ? ? print("Task one finished")

? ? ? ? ? ? ? group.leave()

? ? ? ? ? })

? ? ? }


? ? ? group.enter()

? ? ? queue.async(group: group) {

? ? ? ? ? print("Task two finished")

? ? ? ? ? group.leave()

? ? ? }


? ? ? group.enter()

? ? ? queue.async(group: group) {

? ? ? ? ? print("Task three finished")

? ? ? ? ? group.leave()

? ? ? }


? ? ? group.notify(queue: queue) {

? ? ? ? ? print("All task has finished")

? ? ? }

這下OK了辖试,輸出跟預(yù)期一樣辜王。當(dāng)然這里也可以使用信號(hào)量實(shí)現(xiàn),后面會(huì)介紹罐孝。

Task three finished

Task two finished

Task one finished

All task has finished

信號(hào)量

對(duì)于信號(hào)量的具體內(nèi)容呐馆,可以看我之前寫的一篇博文。使用起來(lái)很簡(jiǎn)單莲兢,創(chuàng)建信號(hào)量對(duì)象汹来,調(diào)用signal方法發(fā)送信號(hào),信號(hào)加1改艇,調(diào)用wait方法等待收班,信號(hào)減1.現(xiàn)在也適用信號(hào)量實(shí)現(xiàn)剛剛的多個(gè)請(qǐng)求功能。

? ? ? let queue = DispatchQueue.global()

? ? ? let group = DispatchGroup()

? ? ? let semaphore = DispatchSemaphore(value: 0)


? ? ? queue.async(group: group) {

? ? ? ? ? DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {

? ? ? ? ? ? ? semaphore.signal()

? ? ? ? ? ? ? print("Task one finished")

? ? ? ? ? })

? ? ? ? ? semaphore.wait()

? ? ? }

? ? ? queue.async(group: group) {

? ? ? ? ? DispatchQueue.main.asyncAfter(deadline: .now() + 0.8, execute: {

? ? ? ? ? ? ? semaphore.signal()

? ? ? ? ? ? ? print("Task two finished")

? ? ? ? ? })

? ? ? ? ? semaphore.wait()

? ? ? }

? ? ? queue.async(group: group) {

? ? ? ? ? print("Task three finished")

? ? ? }


? ? ? group.notify(queue: queue) {

? ? ? ? ? print("All task has finished")

? ? ? }

Suspend / Resume

Suspend可以掛起一個(gè)線程谒兄,即暫停線程摔桦,但是仍然暫用資源,只是不執(zhí)行

Resume回復(fù)線程承疲,即繼續(xù)執(zhí)行掛起的線程酣溃。

循環(huán)執(zhí)行任務(wù)

之前使用GCD的dispatch_apply()執(zhí)行多次任務(wù)瘦穆,現(xiàn)在是調(diào)用concurrentPerform(),下面是并發(fā)執(zhí)行5次

? ? DispatchQueue.concurrentPerform(iterations: 5) {

? ? ? ? print("\($0)")

? ? }

DispatchSource

DispatchSource提高了相關(guān)的API來(lái)監(jiān)控低級(jí)別的系統(tǒng)對(duì)象,比如:Mach ports, Unix descriptors, Unix signals, VFS nodes赊豌。并且能夠異步提交事件到派發(fā)列隊(duì)執(zhí)行扛或。

簡(jiǎn)單定時(shí)器

? ? // 定時(shí)時(shí)間

? ? var timeCount = 60

? ? // 創(chuàng)建時(shí)間源

? ? let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())

? ? timer.schedule(deadline: .now(), repeating: .seconds(1))

? ? timer.setEventHandler {

? ? ? ? timeCount -= 1

? ? ? ? if timeCount <= 0 { timer.cancel() }

? ? ? ? DispatchQueue.main.async {

? ? ? ? ? ? // update UI or other task

? ? ? ? }

? ? }

? ? // 啟動(dòng)時(shí)間源

? ? timer.resume()

對(duì)于比使用Timer的好處可以看這里

應(yīng)用場(chǎng)景

多個(gè)任務(wù)依次執(zhí)行

最容易想到的就是創(chuàng)建一個(gè)串行列隊(duì),然后添加任務(wù)到列隊(duì)執(zhí)行碘饼。

? ? let serialQueue = DispatchQueue(label: "com.my.queue")

? ? serialQueue.async {

? ? ? print("task one")

? ? }

? ? serialQueue.async {

? ? ? print("task two")

? ? }

? ? serialQueue.async {

? ? ? print("task three")

? ? }

其次就是使用前面講到的DispatchGroup熙兔。

取消DispatchWorkItem的任務(wù)

直接取消任務(wù)

? ? let queue = DispatchQueue(label: "queue", attributes: .concurrent)

? ? let workItem = DispatchWorkItem {

? ? ? ? print("done")

? ? }


? ? DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {

? ? ? ? queue.async(execute: workItem) // not work

? ? }

? ? workItem.cancel()

直接調(diào)用取消,異步任務(wù)不會(huì)執(zhí)行艾恼。

執(zhí)行的過(guò)程中取消任務(wù)

? ? func cancelWork() {

? ? ? ? let queue = DispatchQueue.global()

? ? ? ? var item: DispatchWorkItem!


? ? ? ? // create work item

? ? ? ? item = DispatchWorkItem { [weak self] in

? ? ? ? ? ? ? for i in 0 ... 10_000_000 {

? ? ? ? ? ? ? ? ? if item.isCancelled { break }

? ? ? ? ? ? ? ? ? print(i)

? ? ? ? ? ? ? ? ? self?.heavyWork()

? ? ? ? ? ? ? }

? ? ? ? ? ? ? item = nil? ? // resolve strong reference cycle

? ? ? ? }


? ? ? ? // start it

? ? ? ? queue.async(execute: item)


? ? ? ? // after five seconds, stop it if it hasn't already

? ? ? ? queue.asyncAfter(deadline: .now() + 5) { [weak item] in

? ? ? ? ? ? ? ? item?.cancel()

? ? ? ? }

? ? }

具體詳情看這里住涉,也可以了解這篇文章

注意事項(xiàng)

線程死鎖

不要在主列隊(duì)中執(zhí)行同步任務(wù),這樣會(huì)造成死鎖問(wèn)題钠绍。

————————————————

版權(quán)聲明:本文為CSDN博主「Longshihua」的原創(chuàng)文章舆声,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明柳爽。

原文鏈接:https://blog.csdn.net/longshihua/article/details/79756676

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末媳握,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子磷脯,更是在濱河造成了極大的恐慌蛾找,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赵誓,死亡現(xiàn)場(chǎng)離奇詭異打毛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)俩功,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門幻枉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人诡蜓,你說(shuō)我怎么就攤上這事熬甫。” “怎么了万牺?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)洽腺。 經(jīng)常有香客問(wèn)我脚粟,道長(zhǎng),這世上最難降的妖魔是什么蘸朋? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任核无,我火速辦了婚禮,結(jié)果婚禮上藕坯,老公的妹妹穿的比我還像新娘团南。我一直安慰自己噪沙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布吐根。 她就那樣靜靜地躺著正歼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拷橘。 梳的紋絲不亂的頭發(fā)上局义,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音冗疮,去河邊找鬼萄唇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛术幔,可吹牛的內(nèi)容都是我干的另萤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诅挑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼四敞!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起揍障,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤目养,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后毒嫡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體癌蚁,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年兜畸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了努释。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咬摇,死狀恐怖伐蒂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肛鹏,我是刑警寧澤逸邦,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站在扰,受9級(jí)特大地震影響缕减,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芒珠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一桥狡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦裹芝、人聲如沸部逮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)兄朋。三九已至,卻和暖如春炬搭,著一層夾襖步出監(jiān)牢的瞬間蜈漓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工宫盔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留融虽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓灼芭,卻偏偏與公主長(zhǎng)得像有额,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子彼绷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 測(cè)試環(huán)境:Xcode9巍佑,Swift4 一.創(chuàng)建一個(gè)DispatchQueue,并為你的隊(duì)列提供一個(gè)label寄悯。建議...
    天子望氣閱讀 1,994評(píng)論 0 0
  • 在向隊(duì)列中添加任務(wù)時(shí)萤衰,可以直接在對(duì)應(yīng)的函數(shù)中添加 block。但是如果想對(duì)任務(wù)進(jìn)行操作猜旬,比如監(jiān)聽任務(wù)脆栋、取消任務(wù),就...
    fuyoufang閱讀 9,018評(píng)論 3 23
  • 1洒擦,Swift繼續(xù)使用Object-C原有的一套線程椿争,包括三種多線程編程技術(shù): (1)Thread (2)Coco...
    yunxiu閱讀 927評(píng)論 0 1
  • GCD并發(fā)async & sync 很多程序都有一個(gè)主線程,對(duì)于iOS/MacOS開發(fā)來(lái)說(shuō),這個(gè)線程就是UI線程熟嫩,...
    大軍的閱讀 1,086評(píng)論 0 0
  • iOS中GCD的使用小結(jié) 作者dullgrass 2015.11.20 09:41*字?jǐn)?shù) 4996閱讀 20199...
    DanDanC閱讀 832評(píng)論 0 0