10

iOS开发随笔——异步编程

 3 years ago
source link: https://yuguo.us/weblog/ios-develop-3/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Grand Central Dispatch 简称(GCD,这个缩写有点大不敬……)是苹果公司开发的一种多线程技术,它提供了一个比较简单的接口来让开发者操作多线程,而不用关心太多底层实现。

Blocks

首先要知晓的一个概念就是Blocks。在其他语言中,Blocks实际上就是闭包。它定义了一小片代码去运行。你可以把它认为是一种华丽的回调函数,在他们接收到数据的时候就可以去 运行。

Block的语法是这样的:

^{ printf("this is a block!\n"); }     

Dispatch Queues

基本上你会吧blocks放在dispatch queues(派遣队列)中去执行。有两种队列,并行队列,和FIFO(First in First out)队列。无论是那种队列,你放在某一个派遣队列中的各个blocks都会按顺序去执行。不同的是,再并行队列中,它们会在不同的线程中去运行,而再FIFO队列中,它们会一个接一个去运行,要等前一个完成才进行下一个。

你可以通过这三种方法获得一个队列:

  1. 调用 `dispatch_get_global_queue()`。这样会得到内置的并行队列。有三个内置的并行队列,每一个有不同的优先级(低,中,高)
  2. 调用 `dispatch_get_main_queue()`。这样会得到主线程的派遣队列。这是一个FIFO的队列,任务随时都在运行(也就是说处于运行循环之中)
  3. 创建你自己的队列 `dispatch_queue_create()`。这样你会创建一个自己的FIFO队列。

并行队列会创建尽量多的线程来。线程数目是由GCD来决定,而不是你的任务数量,对于这一点开发者并没有控制权,事实上也无需关注。开发者只需要知道队列中的任务会大体上并行运行。

队列VS线程

队列跟线程没有关系。

有一个方法 dispatch_get_current_queue() 可以在一个block中运行,来获取当前的队列,如果再block外部运行会得到默认的并行队列,这没有多大意义。(这其实是第四种方法来获得一个队列)

而如果你创建一个线程,它跟GCD没有任何关系。

使用GCD的派遣队列和block几乎可以完成你用线程实现的任何任务。你甚至可以不用锁就可以实现同步。

如果要开始一个异步任务,要使用dispatc_async()方法。比如如果我们想运行上面的block,这就是我们的代码:

	dispatch_queue_t queue = dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

	dispatch_async(queue, ^{ printf("this is a block!\n"); }); 

这就是全部代码。首先我们得到全局并行队列中的一个(总共有三个,还记得吗?),优先级为普通,然后我们调用dispatch_async,指定这个队列还有一个要运行的block。

block的行为就像闭包,他们会跟自己的运行的上下文环境去交换信息。

int i = 20;    

dispatch_async(queue, ^{ printf("The number was %d\n", i); });     
The number was 20     

block在创建的时候,所有的变量都可以在block的执行中获得,所以我们可以在block中获得i变量。

如果在block中运行任务结束之后需要让主线程知道,可以再次使用dispatch_async:

dispatch_async(queue, ^{ NSArray *results = ComputeBigKnarlyThingThatWouldBlockForAWhile();    

 // tell the main thread     

 dispatch_async(dispatch_get_main_queue(), ^{ ProcessResults(results); });     

});     

这样,在这个长任务完成之后,我们再次调用dispatch_async()来在主线程中运行ProcessResults。

我写字的地方迁移到公众号啦~欢迎关注我的公众号:余果专栏


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK