您的位置:首页 > 移动开发 > IOS开发

疯狂iOS讲义(下)——多线程第二天学习笔记

2015-11-06 20:52 281 查看
注意:iOS规定,只能在UI线程中修改UI控件的属性。

【原因:加入程序允许任意子线程访问。修改UI控件的属性,就需要对多个新线程的并发访问进行同步控制;否则,多个线程将会破坏UI控件内部状态的完整性。】——分工明确,确保不出现错乱。

由于iOS不允许在新线程中修改UI控件的属性,当子线程执行“任务”完成后,如果需要通过UI控件来显示子线程中的数据,通常会调用performSelectorOnMainThread:withObject:waitUntilDone:方法完成。

2.5改变线程的优先级

优先级高的线程获得较多的执行机会,每个子线程的默认优先级为0.5。

NSThread提供了如下的实例方法和类方法来设置获取线程的优先级:

+threadPriority:该类方法获取当前正在执行的线程的优先级。

-threadPriority:该实例方法获取调用该方法的线程对象的优先级。

+setThreadPriority:(double)priority;该类方法用于设置当前正在执行的线程的优先级。

-setThreadPriority:(double)priority;该实例方法用于设置该方法的线程对象的优先级。

double类型的参数范围为:0.0~1.0;

3.线程同步与线程通信

解决方法:

使用@synchronized实现同步。

使用同步锁NSLock,显示定义同步锁对象来实现同步。

【本节内容待补充】

4.使用GCD事项多线程

为了简化多线程应用的开发,iOS提供了GCD来实现多线程。

GCD的2个核心概念:

队列:队列负责管理开发者提交的任务,GCD队列时钟以FIFO(先进先出)的方式来处理人呢无——但由于任务的执行时间并不相同,因此先处理的任务并不一定先结束。队列即可是串行队列,也可是并发队列,串行队列每次只处理一个任务,必须前一个任务执行完成后,才能执行下一个任务;并发队列则可同时处理多个任务,因此将会有多个任务并发执行。

队列底层会维护一个线程池来处理用户提交的任务,线程池的作用就是执行队列管理的任务。串行队列底层的线程池只要维护一个线程即可,并发队列的底层则需要维护多个线程。

任务:任务就是用户提交给队列的工作单元,这些任务将会提交给队列底层维护的线程池执行,因此这些任务会以多线程的方式执行。

使用GCD只要遵守两个步骤即可:

创建队列。

将任务提交给队列。

4.1创建队列

GCD的队列可分为两种

串行队列:串行队列底层的线程池只要一个线程,因此只提供一个线程用来执行任务,所以后一个人任务必须等到前一个任务执行结束才能开始执行。

并发队列:线程池提供多个线程来执行任务,所以可以按FIFO的顺序并发启动、执行多个并发任务。

下面函数用于创建或访问队列

(1)dispatch_queue_t dispatch_get_current_queue(void):获取当前执行代码所在的队列。

(2)dispatch_queue_t dispatch_get_global_queue(long priority,unsigned long flags):根据制定优先级、额外的旗标来获取系统的全局并发队列。第1个参数可接受DISPATCH_QUEUE_PRIORITY_HIGH(2)

DISPATCH_QUEUE_PRIORITY_DEFAULT(0)

DISPATCH_QUEUE_PRIORIT_LOW(-2)

DISPATCH_QUEUE_PRIORITY_BACKGROUND

这几个优先级。目前第2个参数(额外的旗标参数)暂未使用,只是为将来做准备的,一般传入0即可。

(3)dispatch_queue_t dispatch_get_main_queue(void):获取应用主线程所关联的串行队列。

(4)dispatch_queue_t dispatch_queue_create(const char *label,dispatch_queue_attr_t attir):根据制定字符标签创建队列。第2个参数可控制创建串行队列还是并发队列,如果将第2个参数设为”DISPATCH_QUEUE_SERIAL”,则代表穿件串行队列;如果将第2个参数设为”DISPATCH_QUEUE_CONCURRENT”,则代表创建并发队列。在没有启用ARC机制的情况下,通过这种方式创建的队列需要调用dispatch_release()函数释放引用计数。

(5)const char *dispatch_queue_get_label(dispatch_queue_t queue):获取制定队列的字符串标签。

上面函数中涉及一个dispatch_queue_t,这种类型就代表了一个队列。

根据上面函数,程序可以创建如下几种队列。

(1)获取系统默认的全局并发队列:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT , 0);

(2)获取系统主线程关联的串行队列:

dispatch_queue_t queue = dispatch_get_main_queue();

如果将任务提交给主线程关联的串行队列,那么就相当于直接在程序主线程中去执行该任务。

(3)创建串行队列

dispatch_queue_t queue = dispatch_queue_create(“fkjava.queue” ,DISPATCH_QUEUE_SERIAL):

如果将多个任务提交给串行队列,多个任务只能按顺序执行,必须等前一个任务完成后,才能开始执行后一个任务。

(4)创建并发队列

dispatch_queue_t queue = dispatch_queue_create(“fkjava.queue” ,DISPATCH_QUEUE_CONCURRENT);

如果将多个任务提交给并发队列,并发队列可以按FIFO的顺序启动多个并发执行的任务,由于任务的耗时长短并不相同,因此后提交得任务完全可能先完成。

4.2 异步提交任务

iOS提供了如下函数来向队列提交任务。下面这些函数很多都有两个版本:一个接受代码块作为参数的版本,一个接收函数作为参数的版本——其中接受函数作为参数的函数名最后多了_f后缀,而且会多一个参数,用于向函数传入应用程序定义的上下文。

(1)void dispatch_async(dispatch_queue_t queue, dispatch_block_t block):将代码块以异步方式提交给指定队列,该队列底层的线程池将负责执行该代码块。

(2)void dispatch_async_f(dispatch_queue_t queue,void *context, dispatch_function_t work):将函数以异步方式提交给指定队列,该队列底层的线程池将负责执行该函数。

(3)void dispatch_sync(dispatch_queue_t queue ,dispatch_block_t block):将代码块以同步方式提交给指定队列,该队列底层的线程池将负责执行该代码块。

(4)void dispatch_sync_f(dispatch_queue_t queue, void *context ,dispatch_function_t work):将函数以异步方式调教给指定队列,该对列底层的线程池将负责执行该函数。

(5)void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block):将代码块以异步方式提交给指定队列,该队列底层的线程池将负责在when指定的时间点执行该代码块。

(6)void dispatch_after_f(dispatch_time_t when ,dispatch_queue_t queue, void *context, dispatch_function_t work):将函数以异步方式提交给指定队列,该队列底层的线程池将负责在when指定的时间点执行该函数。

(7)void dispatch_apply(size_t iterations, dispatch_queue_t queue, void(^block)(size_t)):将代码块以异步方式提交给指定队列,该队列底层的线程池会多次重复执行该代码块。

(8)void dispatch_apply_f(size_t iterations, dispatch_queue_t queue, void *context, void(*work)(void*,size_t)):将函数以异步方式提交给指定队列,该队列底层的线程池将会多次重复执行该函数。

(9)void dispatch_once_t *predicate, dispatch_block_t block):将代码块提交给指定队列,该队列底层的线程池控制在应用的某个生命周期内禁止性该函数一次。其中predicate参数是一个执行dispatch_once_t(本质就是long型整数)变量的指针,该变量用于判断该代码块是否已经执行过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: