iOS GCD使用
Grand Central Dispatch(GCD)是异步运行任务的技术之中的一个。
一般将应用程序中记述的线程管理用的代码在系统级中实现。开发人员仅仅须要定义想运行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划运行任务。因为线程管理是作为系统的一部分来实现的。因此可统一管理。也可运行任务,这样就比曾经的线程更有效率。
Dispatch Queue
Dispatch Queue是用来运行任务的队列,是GCD中最主要的元素之中的一个。
Dispatch Queue分为两种:
- Serial Dispatch Queue,按加入进队列的顺序(先进先出)一个接一个的运行
- Concurrent Dispatch Queue。并发运行队列里的任务
let myQueue: dispatch_queue_t = dispatch_queue_create("com.xxx", nil)
第一个參数是队列的名称,通常是使用倒序的全域名。
尽管能够不给队列指定一个名称,可是有名称的队列能够让我们在遇到问题时更好调试;当第二个參数为nil时返回Serial Dispatch Queue,如上面那个样例。当指定为DISPATCH_QUEUE_CONCURRENT时返回Concurrent Dispatch Queue。
须要注意一点,假设是在OS X 10.8或iOS 6以及之后版本号中使用,Dispatch Queue将会由ARC自己主动管理,假设是在此之前的版本号。须要自己手动释放,例如以下:
let myQueue: dispatch_queue_t = dispatch_queue_create("com.xxx", nil)
dispatch_async(myQueue, { () -> Void in
println("in Block")
})
dispatch_release(myQueue)
以上是通过手动创建的方式来获取Dispatch Queue,另外一种方式是直接获取系统提供的Dispatch Queue。
要获取的Dispatch Queue无非就是两种类型:
- Main Dispatch Queue
- Global Dispatch Queue / Concurrent Dispatch Queue
//获取Main Dispatch Queue
let mainQueue = dispatch_get_main_queue()
//获取Global Dispatch Queue
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_after
dispatch_after能让我们加入进队列的任务延时运行,比方想让一个Block在10秒后运行:
var time = dispatch_time(DISPATCH_TIME_NOW, (Int64)(10 * NSEC_PER_SEC))
dispatch_after(time, globalQueue) { () -> Void in
println("在10秒后运行")
}
NSEC_PER_SEC表示的是秒数,它还提供了NSEC_PER_MSEC表示毫秒。
获取一个dispatch_time_t类型的值能够通过两种方式来获取,以上是第一种方式。即通过dispatch_time函数。还有一种是通过dispatch_walltime函数来获取,dispatch_walltime须要使用一个timespec的结构体来得到dispatch_time_t。通常dispatch_time用于计算相对时间。dispatch_walltime用于计算绝对时间。我写了一个把NSDate转成dispatch_time_t的Swift方法:
func getDispatchTimeByDate(date: NSDate) -> dispatch_time_t {
let interval = date.timeIntervalSince1970
var second = 0.0
let subsecond = modf(interval, &second)
var time = timespec(tv_sec: __darwin_time_t(second), tv_nsec: (Int)(subsecond * (Double)(NSEC_PER_SEC)))
return dispatch_walltime(&time, 0)
}
这种方法接收一个NSDate对象,然后把NSDate转成dispatch_walltime须要的timespec结构体,最后再把dispatch_time_t返回,相同是在10秒后运行,之前的代码在调用部分须要改动成:
var time = getDispatchTimeByDate(NSDate(timeIntervalSinceNow: 10))
dispatch_after(time, globalQueue) { () -> Void in
println("在10秒后运行")
}
dispatch_group
这个时候就须要使用dispatch_group了:
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let group = dispatch_group_create()
dispatch_group_async(group, globalQueue) { () -> Void in
println("1")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("2")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("3")
}
dispatch_group_notify(group, globalQueue) { () -> Void in
println("completed")
}
- 312
- completed
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let group = dispatch_group_create()
dispatch_group_async(group, globalQueue) { () -> Void in
println("1")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("2")
}
dispatch_group_async(group, globalQueue) { () -> Void in
println("3")
}
//使用dispatch_group_wait函数
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
println("completed")
能够注意到dispatch_group_wait的第二个參数是指定超时的时间,假设指定为DISPATCH_TIME_FOREVER(如上面这个样例)则表示会永久等待,直到上面的Block所有运行完。除此之外。还能够指定为详细的等待时间。依据dispatch_group_wait的返回值来推断是上面block运行完了还是等待超时了。
dispatch_barrier_async
dispatch_barrier_async就如同它的名字一样,在队列运行的任务中添加“栅栏”,在添加“栅栏”之前已经開始运行的block将会继续运行,当dispatch_barrier_async開始运行的时候其它的block处于等待状态,dispatch_barrier_async的任务运行完后,其后的block才会运行。我们简单的写个样例。如果这个样例有读文件和写文件的部分:
func writeFile() {
NSUserDefaults.standardUserDefaults().setInteger(7, forKey: "Integer_Key")
}
func readFile(){
print(NSUserDefaults.standardUserDefaults().integerForKey("Integer_Key"))
}
NSUserDefaults.standardUserDefaults().setInteger(9, forKey: "Integer_Key")
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_barrier_async(globalQueue) {self.writeFile() ; self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
dispatch_async(globalQueue) {self.readFile()}
假设加入dispatch_barrier_async的时候,已经有block在运行了,那么dispatch_barrier_async会等这些block运行完后再运行。
dispatch_apply
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_apply(10, globalQueue) { (index) -> Void in
print(index)
}
print("completed")
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(globalQueue, { () -> Void in
dispatch_apply(10, globalQueue) { (index) -> Void in
print(index)
}
print("completed")
})
print("在dispatch_apply之前")
dispatch_suspend / dispatch_resume
//暂停
dispatch_suspend(globalQueue)
//恢复
dispatch_resume(globalQueue)
Dispatch Semaphore
其他想进入该关键代码段的线程必须等待前面的线程释放信号量。
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let semaphore = dispatch_semaphore_create(1)
for i in 0 ... 9 {
dispatch_async(globalQueue, { () -> Void in
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
let time = dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC))
dispatch_after(time, globalQueue) { () -> Void in
print("2秒后运行")
dispatch_semaphore_signal(semaphore)
}
})
}
dispatch_once
class SingletonObject {
class var sharedInstance : SingletonObject {
struct Static {
static var onceToken : dispatch_once_t = 0
static var instance : SingletonObject? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = SingletonObject()
}
return Static.instance!
}
}