iOS开发之常用技术点

iOS与OS X多线程和内存管理(三)Grand Central

2018-08-22  本文已影响36人  丁宝2012

前言

该篇内容是《iOS与OS X多线程和内存管理》一书中的最后内容了,GCD的学习除了书本的学习,我还结合了一些优秀的第三方类库的源码进行学习,可能学习的不够透彻但已经是收益匪浅,以下内容如有理解错误的地方,希望大家指出,我们一起学习和探讨~

Grand Central Dispatch(GCD)概要

1、什么是GCD

2、多线程编程

int main(){
  id o = [[MyObject alloc] init];
  [o execBlock];
  return o;
}
160D25D4D00934E5CA9CECEE5626BE27.jpg B9BF2555C48C38643CB930AF65ED176B.jpg 848B5841E171F42B7E55BFCDC348349E.jpg DD84731D74D7104C64FEA650F1CDB050.jpg A1EA962F1780B541A7C5B81C4F2CEA0B.jpg

GCD的API

1、Dispatch Queue

 /*
  * 使用Block语法‘定义想执行的任务’
  * 通过dispatch_async函数‘追加’赋值在变量queue的Dispatch Queue中
  * 该代码就可使指定的Block在另一个线程中执行
  */
dispatch_async(queue, ^{
 /*
  *想执行的任务
  */
});
CA2F5A9C817FE2D0697D5CAE066E8EAA.jpg F1DBA7552B1529D0AA71E3E0614F41F5.jpg
/*
 * 当变量queue为Serial Dispatch Queue时,因为等待现在执行中的处理结束,所以首先执行blk0,blk0 执行结束后接着执行blk1,blk1 执行结束后接着执行blk2,如此重复
 * 同时执行的处理数只能时1个
 */
dispatch_async(queue , blk0);
dispatch_async(queue , blk1);
dispatch_async(queue , blk2);
dispatch_async(queue , blk3);
dispatch_async(queue , blk4);
dispatch_async(queue , blk5);
dispatch_async(queue , blk6);
dispatch_async(queue , blk7);

//执行顺序
blk0
blk1
blk2
blk3
blk4
blk5
blk6
blk7
0AFBC313AF59933526838E6B838F0125.jpg
dispatch_async(queue , blk0);
dispatch_async(queue , blk1);
dispatch_async(queue , blk2);
dispatch_async(queue , blk3);
dispatch_async(queue , blk4);
dispatch_async(queue , blk5);
dispatch_async(queue , blk6);
dispatch_async(queue , blk7);
5277F761A842FE19E2838052E0D9771B.jpg

2、dispatch_queue_create

/*
 * 第一个参数:指定Dispatch Queue名称(推荐使用应用程序ID这种逆序全程域名,该名称便与调试)
 * 第二个参数:Serial Dispatch Queue指定为NULL;Concurrent Dispatch Queue指定为DISPATCH_QUEUE_CONCURRENT
 * dispatch_queue_create函数的返回值为表示Dispatch Queue的‘ dispatch_queue_t类型’
 * dispatch_queue_create函数生成的Dispatch Queue必须程序员自己负责释放
 * Dispatch Queue也像OC的引用计数式内存管理一样,需要通过dispatch_retain函数和dispatch_release函数的引用计数来管理内存
 * 在dispatch_async函数中追加Block到Dispatch Queue(该Block通过dispatch_retain函数持有Dispatch Queue(无论Serial Dispatch Queue、Concurrent Dispatch Queue都一样))
 * 一旦Block执行结束,就要通过dispatch_release函数函数释放该Block持有的Dispatch Queue
 * 在dispatch_async函数中追加Block到Dispatch Queue后,即是立刻释放Dispatch Queue,该Dispatch Queue由于被Block持有也不会废弃,因而Block能够执行,Block执行结束后释放该Block持有的Dispatch Queue,这时谁都不持有Dispatch Queue,因此它被废弃
 */
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create ("com.example.MySerialDispatchQueue" , NULL);

dispatch_async(queue, ^{
});

dispatch_release(mySerialDispatchQueue)

E34B95EECA51F78914DF1BE2715DC063.jpg

3、Main Dispatch Queue / Global Dispatch Queue

09E13F95CA2B7304ED0934AD0F836A6F.jpg 211147A30958888874A111D25925639E.jpg 8B4DE7FBBBF733F9A9039209B03C873F.jpg DCE8A4AC936F2C63E0750EEFA5BCCD95.jpg

4、dispatch_set_target_queue

dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue",NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_PRIORITY_BACKGROUND ,0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);
/*
 * 指定要变更执行优先级的Dispatch Queue为dispatch_set_target_queue函数的第一个参数
 * 指定与要使用的执行优先级相同优先级的Dispatch Queue为第二个参数(目标)
 * Main Dispatch Queue和Global Dispatch Queue不可指定为第一个参数
 */
308E070E6A9E7F67FB9A2F50FA0C6665.jpg

5、dispatch_after

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW , 3ull * NSEC_PER_SEC);
dispatch_after(time , dispatch_get_main_queue(), ^{
  NSLog(@"waited at least three seconds ");
});
/*
 * 注意:dispatch_after函数并不是在指定时间后执行处理,而只是在指定时间追加处理到Dispatch Queue,上述代码与3秒后用dispatch_async函数追加Block到Main Dispatch Queue的相同
 * 因为Main Dispatch Queue在主线程的RunLoop中执行,所以在比如每隔1/60秒执行的RunLoop中,Block最快在3秒后执行,最慢在3秒+1/60秒后执行,并且在Main Dispatch Queue有大量处理追加或主线程的处理本身有延迟是,这个时间回更长
 * 第二个参数:指定要追加处理的Dispatch Queue
 * 第三个参数:指定记述要执行处理的Block
 * 第一个参数:指定时间用的dispatch_time_t类型的值
 */

6、Dispatch Group

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{ NSLog(@"blk0");});
dispatch_group_async(group, queue, ^{ NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{ NSLog(@"blk2");});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"done");});
dispatch_release(group);

//执行结果
blk1
blk2
blk0
done
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{ NSLog(@"blk0");});
dispatch_group_async(group, queue, ^{ NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{ NSLog(@"blk2");});

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW , 1ull * NSEC_PER_SEC);
long result = dispatch_group_wait(group , time);
if(result == 0){
  //属于Dispatch Group的全部处理执行结束
}eles{
  //属于Dispatch Group的某一个处理还在执行
}

7、dispatch_barrier_async

dispatch_queue_t queue = dispatch_queue_create("com.example.gcd.Forbarrier",DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk1_for_reading);
dispatch_async(queue, blk2_for_reading);
dispatch_async(queue, blk3_for_reading);
dispatch_barrier_async(queue, blk_for_writing);
dispatch_async(queue, blk4_for_reading);
dispatch_async(queue, blk5_for_reading);
dispatch_async(queue, blk6_for_reading);
dispatch_async(queue, blk7_for_reading);

dispatch_release(queue);
4660EEE669D58074804C874EA0C78C1D.jpg

8、dispatch_sync

98AB491CB48C7FEDFDE1FFC8AFB13B91.jpg 810954A9198B3F33CC7B467AAD70692E.jpg
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{NSLog(@"Hello");});
//Main Dispatch Queue即主线程中执行的Block等待Main Dispatch Queue中执行的Block执行结束(形成死锁)

9、dispatch_apply

/*
 * 第一个参数:重复次数
 * 第二个参数:追加对象的Dispatch Queue
 * 第三个参数:为追加的处理
 */
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRORITY_DEFAULT,0);
dispatch_apply(10, queue, ^(size_t index){
   NSLog(@"%zu",index);
});
NSLog(@"done");

//执行结果
4
1
0
3
5
2
6
8
9
7
done
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRORITY_DEFAULT,0);
//在Global Dispatch Queue中非同步执行

dispatch_async(queue, ^{
 
    //Global Dispatch Queue,等待dispatch_apply函数中全部处理执行结束
    dispatch_apply([array count], queue, ^(size_t index){
   
       //并列处理包含在NSArray对象的全部对象  
       NSLog(@"%zu :%@",index,[array objectAtIndex:index]);

    });
    //dispatch_apply函数中的处理全部执行结束

   //在Main Dispatch Queue中非同步执行
   dispatch_async(dispatch_get_main_queue(),^{
     //在Main Dispatch Queue中执行处理
     NSLog(@"done");
  });

});

10、dispatch_suspend/dispatch_resume

//dispatch_suspend函数挂起指定的Dispatch Queue
dispatch_suspend(queue)
//dispatch_suspend函数恢复指定的Dispatch Queue
dispatch_resume(queue)

11、Dispatch Semaphore

/* 
 * 使用dispatch_semaphore_create函数生成Dispatch Semaphore
 * 参数表示计数的初始值
 * 函数名称中包含create,必须自己通过dispatch_release函数释放,和dispatch_retain函数持有
 */
dispatch_semaphore_t  semaphore = dispatch_semaphore_create(1);
/*
 * dispatch_semaphore_wait函数等待Dispatch Semaphore的计数值达到大于或等于1
 * 当计数大于等于1,或者待机中计数值大于等于1时,对该计数进行减法并从dispatch_semaphore_wait函数返回
 * 第二个参数:等待时间
 */
dispatch_semaphore_wait  (semaphore, DISPATCH_TIME_FOREVER);
46EFE57F9F6B581F762BE7E601596DF1.jpg 443268CA18DBEFD31E458C8DBCA3D489.jpg 052A16CBE19578234C65672A9BBA8BC8.jpg

12、dispatch_once

总结

《iOS与OS X多线程和内存管理》整本书已经完成了简单的笔记整理,在学习这本书的时候,我以单元为单位,第一遍进行粗略阅读,整体了解该章节的内容,然后第二遍开始仔细阅读并且整理笔记,这样感觉记忆和理解的更为深刻,然后就该章节在配合《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法 》书中对应的内容再次学习,又一次的扩充了该知识点。当然如此经典的书,每一次阅读都会有不同的理解,都会学到不同的东西,有时间我会再学习,有新的理解会及时更新整理文章内容,文笔有限,希望大家包涵,这是我在这次读书时总结的心得经验,希望对大家有帮助

上一篇下一篇

猜你喜欢

热点阅读