一、GCD的使用
1 // 2 // ViewController.m 3 // IOS_0117_GCD 4 // 5 // Created by ma c on 16/1/17. 6 // Copyright (c) 2016年 博文科技. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 11 @interface ViewController () 12 13 @end 14 /* 15 一、简介 16 1.什么是GCD 17 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 18 纯C语言,提供了非常多强大的函数 19 20 2.GCD的优势 21 GCD是苹果公司为多核的并行运算提出的解决方案 22 GCD会自动利用更多的CPU内核(比如双核、四核) 23 GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程) 24 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码 25 26 二、任务和队列 27 1.GCD中有2个核心概念 28 任务:执行什么操作 29 队列:用来存放任务 30 31 2.GCD的使用就2个步骤 32 定制任务 33 确定想做的事情 34 35 3.将任务添加到队列中 36 GCD会自动将队列中的任务取出,放到对应的线程中执行 37 任务的取出遵循队列的FIFO原则:先进先出,后进后出 38 39 三、执行任务 40 1.GCD中有2个用来执行任务的函数 41 用同步的方式执行任务 42 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); 43 queue:队列 44 block:任务 45 46 2.用异步的方式执行任务 47 dispatch_async(dispatch_queue_t queue, dispatch_block_t block); 48 49 3.同步和异步的区别 50 同步:只能在当前线程中执行任务,不具备开启新线程的能力 51 异步:可以在新的线程中执行任务,具备开启新线程的能力 52 53 四、队列的类型 54 1.GCD的队列可以分为2大类型 55 并发队列(Concurrent Dispatch Queue) 56 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务) 57 并发功能只有在异步(dispatch_async)函数下才有效 58 59 2.串行队列(Serial Dispatch Queue) 60 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务) 61 62 五、容易混淆的术语 63 1.有4个术语比较容易混淆:同步、异步、并发、串行 64 同步和异步主要影响:能不能开启新的线程 65 同步:在当前线程中执行任务,不具备开启新线程的能力 66 异步:在新的线程中执行任务,具备开启新线程的能力 67 68 2.并发和串行主要影响:任务的执行方式 69 并发:多个任务并发(同时)执行 70 串行:一个任务执行完毕后,再执行下一个任务 71 72 73 74 同步串行:在一个与主线程同步的线程中,同步执行任务 75 ps:在计算机中除了主线程外,其余线程都是并行性质 76 异步串行:在与一个主线程不同步的线程中,异步执行任务 77 78 同步并行:线程中多个任务同时向前推进 79 异步并行:线程中多个任务同时进行,但完成度不同 80 81 六、并发队列 82 1.GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建 83 使用dispatch_get_global_queue函数获得全局的并发队列 84 dispatch_queue_t dispatch_get_global_queue( 85 dispatch_queue_priority_t priority, // 队列的优先级 86 unsigned long flags); // 此参数暂时无用,用0即可 87 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列 88 89 2.全局并发队列的优先级 90 #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高 91 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中) 92 #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低 93 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台 94 95 七、串行队列 96 1.GCD中获得串行有2种途径 97 使用dispatch_queue_create函数创建串行队列 98 dispatch_queue_t 99 dispatch_queue_create(const char *label, // 队列名称 100 dispatch_queue_attr_t attr); // 队列属性,一般用NULL即可 101 dispatch_queue_t queue = dispatch_queue_create("cn.itcast.queue", NULL); // 创建 102 dispatch_release(queue); // 非ARC需要释放手动创建的队列 103 104 2.使用主队列(跟主线程相关联的队列) 105 主队列是GCD自带的一种特殊的串行队列 106 放在主队列中的任务,都会放到主线程中执行 107 使用dispatch_get_main_queue()获得主队列 108 dispatch_queue_t queue = dispatch_get_main_queue(); 109 110 八、各种队列的执行效果 111 注意 112 使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列 113 114 九、线程间通信示例 115 1.从子线程回到主线程 116 dispatch_async( 117 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 118 // 执行耗时的异步操作... 119 dispatch_async(dispatch_get_main_queue(), ^{ 120 // 回到主线程,执行UI刷新操作 121 }); 122 }); 123 124 十、延时执行 125 iOS常见的延时执行有2种方式 126 调用NSObject的方法 127 [self performSelector:@selector(run) withObject:nil afterDelay:2.0]; 128 // 2秒后再调用self的run方法 129 130 使用GCD函数 131 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 132 // 2秒后执行这里的代码... 在哪个线程执行,跟队列类型有关 133 134 }); 135 136 十一、一次性代码 137 使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次 138 static dispatch_once_t onceToken; 139 dispatch_once(&onceToken, ^{ 140 // 只执行1次的代码(这里面默认是线程安全的) 141 }); 142 143 十二、队列组 144 1.有这么1种需求 145 首先:分别异步执行2个耗时的操作 146 其次:等2个异步操作都执行完毕后,再回到主线程执行操作 147 148 2.如果想要快速高效地实现上述需求,可以考虑用队列组 149 dispatch_group_t group = dispatch_group_create(); 150 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 151 // 执行1个耗时的异步操作 152 }); 153 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 154 // 执行1个耗时的异步操作 155 }); 156 dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 157 // 等前面的异步操作都执行完毕后,回到主线程... 158 }); 159 160 十三、Core Foundation 161 Foundation : OC 162 Core Foundation : C 163 Foundation和Core Foundation可以相互转化 164 165 NSString *str = @"123"; 166 CFStringRef str2 = (__bridge CFStringRef)str; 167 NSString *str3 = (__bridge NSString *)(str2); 168 169 CFArrayRef --- NSArray 170 CFDictionaryRef --- NSDirectory 171 CFNumberRef --- NSNumber 172 173 凡是函数名中带有create\copy\retain\new等字眼,都应该再不需要的时候进行release 174 GCD的数据类型在ARC环境下不需要release 175 CF(Core Foundation)的数据类型在ARC环境下还需要release 176 177 Core Foundation中手动创建的数据类型,需要手动释放 178 CFArrayRef array = CFArrayCreate(NULL, NULL, 10, NULL); 179 CFRelease(array); 180 181 CGPathRef path = CGPathCreateMutable(); 182 CGPathRelease(path); 183 184 */ 185 @implementation ViewController 186 187 - (void)viewDidLoad { 188 [super viewDidLoad]; 189 190 } 191 192 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 193 { 194 // [self basicUse]; 195 196 // [self asyncGlobleQueue]; 197 // [self asyncSerialQueue]; 198 // [self asyncMainQueue]; 199 200 // [self syncGlobleQueue]; 201 // [self syncSerialQueue]; 202 // [self syncMainQueue]; 203 } 204 205 #pragma mark - 异步 206 207 /** 208 * async(异步) --并发队列(最常用) 209 * 会不会创建线程:会,并且创建多条线程 210 * 任务的执行方式:并发执行 211 */ 212 - (void)asyncGlobleQueue 213 { 214 NSLog(@"asyncGlobleQueue-----begin"); 215 //获得全局并发队列 216 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 217 //将 任务 添加到 全局并发队列 中去 异步执行-开线程 218 dispatch_async(queue, ^{ 219 NSLog(@"\n----下载图片1----%@",[NSThread currentThread]); 220 }); 221 dispatch_async(queue, ^{ 222 NSLog(@"\n----下载图片2----%@",[NSThread currentThread]); 223 }); 224 dispatch_async(queue, ^{ 225 NSLog(@"\n----下载图片3----%@",[NSThread currentThread]); 226 }); 227 dispatch_async(queue, ^{ 228 NSLog(@"\n----下载图片4----%@",[NSThread currentThread]); 229 }); 230 NSLog(@"asyncGlobleQueue-----end"); 231 232 233 } 234 235 /** 236 * async(异步) --串行队列(有时用) 237 * 会不会创建线程:会,创建一条 238 * 线程的执行方法:串行(一个任务执行完毕后,再执行下一个任务) 239 */ 240 - (void)asyncSerialQueue 241 { 242 NSLog(@"asyncSerialQueue-----begin"); 243 244 //创建串行队列 245 dispatch_queue_t queue = dispatch_queue_create("cn.bowen.queue", NULL); 246 247 //将 任务 添加到 串行队列 中去 异步执行-开线程 248 dispatch_async(queue, ^{ 249 NSLog(@"\n----下载图片1----%@",[NSThread currentThread]); 250 }); 251 dispatch_async(queue, ^{ 252 NSLog(@"\n----下载图片2----%@",[NSThread currentThread]); 253 }); 254 dispatch_async(queue, ^{ 255 NSLog(@"\n----下载图片3----%@",[NSThread currentThread]); 256 }); 257 dispatch_async(queue, ^{ 258 NSLog(@"\n----下载图片4----%@",[NSThread currentThread]); 259 }); 260 NSLog(@"asyncSerialQueue-----end"); 261 262 //非ARC需要手动释放串行队列 263 //dispatch_release(queue); 264 } 265 266 267 /** 268 * async(异步) --主队列(很常用)(特殊) 269 * 会不会创建线程:不会 270 * 任务的执行方式:串行 271 * 一般用在线程之间的通讯 272 */ 273 - (void)asyncMainQueue 274 { 275 NSLog(@"asyncMainQueue-------begin"); 276 //主队列(添加到主队列中的任务,自动放到主线程中执行) 277 dispatch_queue_t queue = dispatch_get_main_queue(); 278 //将 任务 添加到 主队列 中去 异步执行(异步失效) 279 dispatch_async(queue, ^{ 280 NSLog(@"\n----下载图片1----%@",[NSThread currentThread]); 281 }); 282 dispatch_async(queue, ^{ 283 NSLog(@"\n----下载图片2----%@",[NSThread currentThread]); 284 }); 285 dispatch_async(queue, ^{ 286 NSLog(@"\n----下载图片3----%@",[NSThread currentThread]); 287 }); 288 dispatch_async(queue, ^{ 289 NSLog(@"\n----下载图片4----%@",[NSThread currentThread]); 290 }); 291 NSLog(@"asyncMainQueue-------end"); 292 293 294 } 295 296 #pragma mark - 同步 297 /** 298 * sync(同步) --主队列(不能用) 299 */ 300 - (void)syncMainQueue 301 { 302 NSLog(@"syncMainQueue-------begin"); 303 //主队列(添加到主队列中的任务,自动放到主线程中执行) 304 dispatch_queue_t queue = dispatch_get_main_queue(); 305 //将 任务 添加到 主队列 中去 异步执行(异步失效) 306 dispatch_sync(queue, ^{ 307 NSLog(@"\n----下载图片1----%@",[NSThread currentThread]); 308 }); 309 dispatch_sync(queue, ^{ 310 NSLog(@"\n----下载图片2----%@",[NSThread currentThread]); 311 }); 312 dispatch_sync(queue, ^{ 313 NSLog(@"\n----下载图片3----%@",[NSThread currentThread]); 314 }); 315 dispatch_sync(queue, ^{ 316 NSLog(@"\n----下载图片4----%@",[NSThread currentThread]); 317 }); 318 NSLog(@"syncMainQueue-------end"); 319 320 } 321 322 /** 323 * sync(同步) --并发队列 324 * 会不会创建线程:不会,在主线程中运行 325 * 任务的执行方式:串行(一个任务执行完毕后,再执行下一个任务) 326 * 并发队列失去并发功能 327 */ 328 - (void)syncGlobleQueue 329 { 330 NSLog(@"syncGlobleQueue----begin"); 331 //获得全局并发队列 332 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 333 //将 任务 添加到 全局并发队列 中去 同步执行 334 dispatch_sync(queue, ^{ 335 NSLog(@"\n----下载图片1----%@",[NSThread currentThread]); 336 }); 337 dispatch_sync(queue, ^{ 338 NSLog(@"\n----下载图片2----%@",[NSThread currentThread]); 339 }); 340 dispatch_sync(queue, ^{ 341 NSLog(@"\n----下载图片3----%@",[NSThread currentThread]); 342 }); 343 dispatch_sync(queue, ^{ 344 NSLog(@"\n----下载图片4----%@",[NSThread currentThread]); 345 }); 346 NSLog(@"syncGlobleQueue----end"); 347 348 349 } 350 /** 351 * sync(同步) --串行队列 352 * 会不会创建线程:不会 353 * 线程的执行方法:串行(一个任务执行完毕后,再执行下一个任务) 354 */ 355 - (void)syncSerialQueue 356 { 357 NSLog(@"syncSerialQueue----begin"); 358 //创建串行队列 359 dispatch_queue_t queue = dispatch_queue_create("cn.bowen.queue", NULL); 360 361 //将 任务 添加到 串行队列 中去 同步执行 362 dispatch_sync(queue, ^{ 363 NSLog(@"\n----下载图片1----%@",[NSThread currentThread]); 364 }); 365 dispatch_sync(queue, ^{ 366 NSLog(@"\n----下载图片2----%@",[NSThread currentThread]); 367 }); 368 dispatch_sync(queue, ^{ 369 NSLog(@"\n----下载图片3----%@",[NSThread currentThread]); 370 }); 371 dispatch_sync(queue, ^{ 372 NSLog(@"\n----下载图片4----%@",[NSThread currentThread]); 373 }); 374 NSLog(@"syncSerialQueue----end"); 375 376 } 377 378 379 #pragma mark - GCD基本使用 380 - (void)basicUse 381 { 382 //获得全局并发队列 383 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 384 //将任务添加到全局队列中去异步执行-开线程 385 dispatch_async(queue, ^{ 386 NSLog(@"\n----下载图片----%@",[NSThread currentThread]); 387 }); 388 389 //在当前(并发)队列中执行同步执行-不开线程 390 dispatch_sync(queue, ^{ 391 NSLog(@"\n----下载图片----%@",[NSThread currentThread]); 392 }); 393 394 } 395 396 @end
原文:http://www.cnblogs.com/oc-bowen/p/5137635.html