GCD的主要方法介绍

来源:互联网 发布:软件升级必然凯文凯利 编辑:程序博客网 时间:2024/04/30 06:58

(1)创建一个队列   
  dispatch_queue_t queue = dispatch_queue_create("LoadImage", NULL);

       其中,第一个参数是标识队列的,第二个参数是用来定义队列的参数(目前不支持,因此传入NULL)。
(2)执行一个队列(async--->异步,sync--->同步)   
  dispatch_async(queue, ^{ [self doSomething]; });

        其中,首先传入之前创建的队列,然后提供由队列运行的代码块。
(3)声明并执行一个队列 (如果不需要保留要运行的队列的引用)
  dispatch_async(dispatch_queue_create ("LoadImage", NULL), ^{ [self doSomething]; });

(4)暂停一个队列   
  dispatch_suspend(queue);

(5)恢复一个队列(如果暂停一个队列不要忘记恢复)

       dispatch_resume(queue);

(6)将代码块中的工作转回到主线程(注意,dispatch_suspend (以及dispatch_resume)在主线程上不起作用)

  dispatch_sync(dispatch_get_main_queue(), ^{ [self dismissLoginWindow]; });

示例:

  1. - (void)setImageWithURL:(NSURL *)url{  
  2.   
  3.     dispatch_queue_t queue = dispatch_queue_create("loadImage"NULL);  
  4.   
  5.     dispatch_async(queue, ^{  
  6.           
  7.         NSData * data = [NSData dataWithContentsOfURL:url];  
  8.         UIImage * image = [UIImage imageWithData:data];  
  9.           
  10.         // 加载UI的操作,一般放在主线程进行  
  11.         dispatch_async(dispatch_get_main_queue(), ^{  
  12.               
  13.             self.image = image;  
  14.         });  
  15.           
  16.     });  
  17. }  
3.引用其他几个方法的介绍:

@dispatch对象

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 原文地址  http://www.cnblogs.com/sunfrog/p/3243230.html  
  2.   
  3. 谈起iOS的dispatch(正式称谓是Grand Central Dispatch或GCD),不得不说这又是iOS(包括MacOSX)平台的创新,优缺点这里不讨论,只有当你使用时才能真正体会到。我们说dispatch函数的主要目的是实现多任务并发代码,那么要理解dispatch函数,先来了解dispatch对象的定义。  
  4.   
  5.    
  6.   
  7. dispatch对象类型的部分定义,主要使用C语言的宏定义:  
  8.   
  9. <os/object.h>文件:  
  10.   
  11. #define OS_OBJECT_CLASS(name) OS_##name  
  12.   
  13. #define OS_OBJECT_DECL(name, ...) \  
  14.   
  15. @protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \  
  16.   
  17. @end \  
  18.   
  19. typedef NSObject<OS_OBJECT_CLASS(name)> *name##_t  
  20.   
  21. #define OS_OBJECT_DECL_SUBCLASS(name, super) \  
  22.   
  23. OS_OBJECT_DECL(name, <OS_OBJECT_CLASS(super)>)  
  24.   
  25.    
  26.   
  27. <dispatch/object.h>文件:  
  28.   
  29. #define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)  
  30.   
  31. #define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))  
  32.   
  33. OS_OBJECT_DECL(dispatch_object); //定义dispatch_object_t  
  34.   
  35.    
  36.   
  37. <dispatch/queue.h>文件(dispatch队列类定义,其它dispatch对象类似):  
  38.   
  39. DISPATCH_DECL(dispatch_queue); //定义dispatch_queue_t  
  40.   
  41.    
  42.   
  43. 可以通过Xcode预编译后可以看到最终结果,最终定义的都是NSObject类,虽然它们之间没用直接继承关系,但都实现OS_dispatch_object接口,这样dispatch_queue_t对象也同样是dispatch_object_t的对象了。下面就是预编译dispatch_object_t和dispatch_queue_t的结果:  
  44.   
  45. @protocol OS_dispatch_object  
  46.   
  47. @end  
  48.   
  49. typedef NSObject<OS_dispatch_object> *dispatch_object_t;  
  50.   
  51. @protocol OS_dispatch_queue <OS_dispatch_object>  
  52.   
  53. @end  
  54.   
  55. typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;  
  56.   
  57.    
  58.   
  59. 由于dispatch api接口定义成C函数的形式,dispatch的对象都是由C函数形式的厂方法得到(不能继承dispatch类,不用alloc),这样做隐藏dispatch对象的具体形态,把注意力放在如何调用dispatch api上。  
  60.   
  61. 从上面dispatch对象宏定义可以看到dispatch对象类的名称一般为dispatch_xyz_t(严格来讲是对象指针),它们都可以看成dispatch_object_t的子类(对象指针),所以使用dispatch对象时套用这个概念就行。  
  62.   
  63.    
  64.   
  65. 有关dispatch对象的基本接口如下:  
  66.   
  67. void dispatch_retain(dispatch_object_t object); //替代dispatch对象常规的retain来持有对象,但ARC编程中不再允许  
  68.   
  69. void dispatch_release(dispatch_object_t object); //替代dispatch对象常规的release来释放对象,同样ARC编程中不再允许  
  70.   
  71. void dispatch_set_context(dispatch_object_t object, voidvoid *context); //给dispatch对象绑定特定数据对象(类似线程的TLS数据),会被传给dispatch对象的finalizer函数  
  72.   
  73. voidvoid *dispatch_get_context(dispatch_object_t object); //返回dispatch对象绑定的数据对象指针  
  74.   
  75. void dispatch_set_finalizer_f(dispatch_object_t object, dispatch_function_t finalizer); //设置dispatch对象的finalizer函数,当该对象释放时会调用finalizer,部分代码解释如何使用这个函数(ARC模式):  
  76.   
  77. dispatch_object_t dispatchObject = ...;  
  78.   
  79. voidvoid *context = ...;  
  80.   
  81. dispatch_set_context(dispatchObject, context);  
  82.   
  83. dispatch_set_finalizer_f(dispatchObject, finalizer);  
  84.   
  85. ......  
  86.   
  87. dispatchObject = nil//dispatchObject被释放,这时调用finalizer函数  
  88.   
  89. ......  
  90.   
  91. void finalizer(voidvoid *context)  
  92.   
  93. {  
  94.   
  95.   //处理或释放context相关资源  
  96.   
  97. }  
  98.   
  99.    
  100.   
  101. dispatch对象的另外两个接口是:  
  102.   
  103. void dispatch_resume(dispatch_object_t object); //激活(启动)在dispatch对象上的block调用,可以运行多个block  
  104.   
  105. void dispatch_suspend(dispatch_object_t object); //挂起(暂停)在dispatch对象上的block调用,已经运行的block不会停止  
  106.   
  107. 一般这两个函数的调用必须成对,否则运行会出现异常。  
  108.   
  109. 至此你是否发现这两个函数有些与众不同呢?好像从来没有这么使用对象的,启动对象--暂停对象,呵呵。这正是理解dispatch对象的关键所在。dispatch对象其实是抽象的任务,把动态的任务变成对象来管理。任务是动态的,不存在继承关系,这就是为什么GCD没有提供静态继承dispatch对象类的方式。如果能这样理解,那么在使用dispatch函数时就能够更灵活地去编写代码,实现各种并发的多任务代码。  
@dispatch源
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 原文地址  http://www.cnblogs.com/sunfrog/p/3243230.html  
  2.   
  3. dispatch源(dispatch source)和RunLoop源概念上有些类似的地方,而且使用起来更简单。要很好地理解dispatch源,其实把它看成一种特别的生产消费模式。dispatch源好比生产的数据,当有新数据时,会自动在dispatch指定的队列(即消费队列)上运行相应地block,生产和消费同步是dispatch源会自动管理的。  
  4. dispatch源的使用基本为以下步骤:  
  5.   
  6. 1. dispatch_source_t source = dispatch_source_create(dispatch_source_type, handler, mask, dispatch_queue); //创建dispatch源,这里使用加法来合并dispatch源数据,最后一个参数是指定dispatch队列  
  7.   
  8. 2. dispatch_source_set_event_handler(source, ^{ //设置响应dispatch源事件的block,在dispatch源指定的队列上运行  
  9.   
  10.   //可以通过dispatch_source_get_data(source)来得到dispatch源数据  
  11.   
  12. });  
  13.   
  14. 3. dispatch_resume(source); //dispatch源创建后处于suspend状态,所以需要启动dispatch源  
  15.   
  16. 4. dispatch_source_merge_data(source, value); //合并dispatch源数据,在dispatch源的block中,dispatch_source_get_data(source)就会得到value。  
  17.   
  18. 是不是很简单?而且完全不必编写同步的代码。比如网络请求数据的模式,就可以这样来写:  
  19.   
  20.     dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 00, dispatch_get_global_queue(00));  
  21.   
  22.     dispatch_source_set_event_handler(source, ^{  
  23.   
  24.         dispatch_sync(dispatch_get_main_queue(), ^{  
  25.   
  26.     //更新UI  
  27.   
  28.         });  
  29.   
  30.     });  
  31.   
  32.     dispatch_resume(source);  
  33.   
  34.     dispatch_async(dispatch_get_global_queue(00), ^{  
  35.   
  36.    //网络请求  
  37.   
  38.         dispatch_source_merge_data(source, 1); //通知队列  
  39.   
  40.     });  
  41.   
  42. dispatch源还支持其它一些系统源,包括定时器、监控文件的读写、监控文件系统、监控信号或进程等,基本上调用的方式原理和上面相同,只是有可能是系统自动触发事件。比如dispatch定时器:  
  43.   
  44. dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 00, queue);  
  45.   
  46. dispatch_source_set_timer(timer, dispatch_walltime(NULL0), 10*NSEC_PER_SEC, 1*NSEC_PER_SEC); //每10秒触发timer,误差1秒  
  47.   
  48. dispatch_source_set_event_handler(timer, ^{  
  49.   
  50.   //定时处理  
  51.   
  52. });  
  53.   
  54. dispatch_resume(timer);  
  55.   
  56. 其它情况的dispatch源就不再一一举例,可参看官网有具体文档: https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/GCDWorkQueues/GCDWorkQueues.html#//apple_ref/doc/uid/TP40008091-CH103-SW1  
  57.   
  58.    
  59.   
  60. 最后,dispatch源的其它一些函数大致罗列如下:  
  61.   
  62. uintptr_t dispatch_source_get_handle(dispatch_source_t source); //得到dispatch源创建,即调用dispatch_source_create的第二个参数  
  63.   
  64. unsignedlong dispatch_source_get_mask(dispatch_source_t source); //得到dispatch源创建,即调用dispatch_source_create的第三个参数  
  65.   
  66. void dispatch_source_cancel(dispatch_source_t source); //取消dispatch源的事件处理--即不再调用block。如果调用dispatch_suspend只是暂停dispatch源。  
  67.   
  68. long dispatch_source_testcancel(dispatch_source_t source); //检测是否dispatch源被取消,如果返回非0值则表明dispatch源已经被取消  
  69.   
  70. void dispatch_source_set_cancel_handler(dispatch_source_t source, dispatch_block_t cancel_handler); //dispatch源取消时调用的block,一般用于关闭文件或socket等,释放相关资源  
  71.   
  72. void dispatch_source_set_registration_handler(dispatch_source_t source, dispatch_block_t registration_handler); //可用于设置dispatch源启动时调用block,调用完成后即释放这个block。也可在dispatch源运行当中随时调用这个函数。  

@dispatch同步
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 原文地址  http://www.cnblogs.com/sunfrog/p/3243230.html  
  2.   
  3. GCD提供两种方式支持dispatch队列同步,即dispatch组和信号量。  
  4. 一、dispatch组(dispatch group)  
  5.   
  6. 1. 创建dispatch组  
  7.   
  8. dispatch_group_t group = dispatch_group_create();   
  9.   
  10. 2. 启动dispatch队列中的block关联到group中  
  11.   
  12. dispatch_group_async(group, queue, ^{   
  13.   
  14.   // 。。。   
  15.   
  16. });   
  17.   
  18. 3. 等待group关联的block执行完毕,也可以设置超时参数  
  19.   
  20. dispatch_group_wait(group, DISPATCH_TIME_FOREVER);   
  21.   
  22. 4. 为group设置通知一个block,当group关联的block执行完毕后,就调用这个block。类似dispatch_barrier_async。  
  23.   
  24. dispatch_group_notify(group, queue, ^{  
  25.   
  26.   // 。。。   
  27.   
  28. });   
  29.   
  30. 5. 手动管理group关联的block的运行状态(或计数),进入和退出group次数必须匹配  
  31.   
  32. dispatch_group_enter(group);  
  33.   
  34. dispatch_group_leave(group);  
  35.   
  36. 所以下面的两种调用其实是等价的,   
  37.   
  38. A)  
  39.   
  40. dispatch_group_async(group, queue, ^{   
  41.   
  42.   // 。。。   
  43.   
  44. });   
  45.   
  46. B)   
  47.   
  48. dispatch_group_enter(group);  
  49.   
  50. dispatch_async(queue, ^{  
  51.   
  52.   //。。。  
  53.   
  54.   dispatch_group_leave(group);  
  55.   
  56. });  
  57.   
  58. 所以,可以利用dispatch_group_enter、 dispatch_group_leave和dispatch_group_wait来实现同步,具体例子:http://stackoverflow.com/questions/10643797/wait-until-multiple-operations-executed-including-completion-block-afnetworki/10644282#10644282。  
  59.   
  60.    
  61.   
  62. 二、dispatch信号量(dispatch semaphore)  
  63.   
  64. 1. 创建信号量,可以设置信号量的资源数。0表示没有资源,调用dispatch_semaphore_wait会立即等待。  
  65.   
  66. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);  
  67.   
  68. 2. 等待信号,可以设置超时参数。该函数返回0表示得到通知,非0表示超时。  
  69.   
  70. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);  
  71.   
  72. 3. 通知信号,如果等待线程被唤醒则返回非0,否则返回0。  
  73.   
  74. dispatch_semaphore_signal(semaphore);  
  75.   
  76. 最后,还是回到生成消费者的例子,使用dispatch信号量是如何实现同步:  
  77.   
  78.    
  79.   
  80. dispatch_semaphore_t sem = dispatch_semaphore_create(0);  
  81.   
  82. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //消费者队列  
  83.   
  84.       while (condition) {  
  85.   
  86.     if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, 10*NSEC_PER_SEC))) //等待10秒  
  87.   
  88.       continue;  
  89.   
  90.     //得到数据  
  91.   
  92.   }  
  93.   
  94. });  
  95.   
  96. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //生产者队列  
  97.   
  98.       while (condition) {  
  99.   
  100.      if (!dispatch_semaphore_signal(sem))  
  101.   
  102.     {  
  103.   
  104.       sleep(1); //wait for a while  
  105.   
  106.       continue;  
  107.   
  108.     }  
  109.   
  110.     //通知成功  
  111.   
  112.   }  
  113.   
  114. });  

0 0
原创粉丝点击