多线程的意义:通过提高系统资源的利用率,充分发挥多核处理器的优势,并发(同时执行)执行任务让系统运行的更快、更流畅
NSThread(目前已经不常用)
在NSThread多线程中最常用的是NSObject封装的多线程方法
-(void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
这个方法可以调用继承自对象中实现的方法通过将其抛入到其他后台线程执行
(SEL即为需要调用的selector; arg为向selector中传递的参数)
这个方法可以修改程序的UI但是强烈不建议使用该方法直接修改界面.
如果需要在该方法中修改UI可以调用控件的
-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
方法来进行修改
performSelectorOnMainThread方法也是在nsobject类中封装的多线程方法,该方法的作用是调用对象中的方法在主线程中执行
当然也可以使用自定义线程的方式来实现多线程:
+(void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
NSThread的工厂方法,快速返回一个NSThread对象,该方法生成的线程会直接启动
-(id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
NSthread的构造函数生成一个NSThread对象,该方法生成的线程对象需要手动调用start方法才能启动
需要注意的是在NSThread方式实现多线程的时候需要给每一个线程定义一个autoreleasepool,否则会出现内存泄露
NSOperation/NSOperationQueue
这是一种面向对象的多线程技术, 因其对另外两种进行了封装,所以相比较其他两种有更加全面的功能;
一般步骤:
- 创建一个NSOperation
- 创建或者获取一个NSOperationQueue
- 将操作添加到队列中
NSOperation分为两个子类
- NSInvocationOperation
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
这个方法有些类似于NSThread 主要就是需要把抛出的操作封装到target的一个对象方法中,可以传一个参数;
- NSBlockOperation(个人感觉最好用的)
+ (id)blockOperationWithBlock:(void (^)(void))block;
工厂方法快速生成一个blockOperation,该方法的好处就是不需要再定义一个方法,而block作为一个参数传递进去可以极大地增强代码的扩展性,降低代码间的耦合度,方便后期维护.
创建好了nsoperation之后就需要将它添加到指定的队列中去了当操作被加入到队列中的时候就立刻处于激活状态开始执行了;
NSOperation的start方法可以将该操作加入到当前的操作队列中.
另外,值得一提的是NSOperation方式实现多线程相比较其他两种最大的好处就是可以限制并发的线程数
-(void) maxConcurrentOperationCount;
这个方法是NSOperationQueue的对象方法,用来限制当前操作队列同时并发的线程数
在一个程序中,每多开一个线程就会多占用一些系统资源,在iOS环境下主线程的栈内存是1M之后每开一个子线程会占用系统512k的栈内存,所以在实际的开发中控制并发的线程数是非常重要的.
NSOperation对象之间的依赖关系:
在多线程开发中,如果几个操作之间有依赖关系是非常令人头疼的一件事,但是NSOperation可以很简单的处理不同线程之间的操作依赖关系例如,有三个操作分别为op1, op2, op3.三个操作需要按照顺序执行代码如下:
[op2 addDependency:op1];
[op3 addDependency:op2];
这种依赖关系并不受所在的操作队列限制也就是说,即使op1,op2处于子线程而且是非常耗时的操作,op3处于主线程.op3也会等到op2执行完毕后才会执行,这样在实际的开发中是非常方便的,因为在开发中操作队列中的操作并不是按照添加顺序来执行的,而添加依赖就保证了它们能够按照规定的顺序执行
Gcd
GCD 是一套基于C语言的框架,发布于iOS4.0,其设计的初衷就是为了更好的发挥多核处理器的优势,底层是通过线程实现的,GCD是苹果官方推荐使用的多线程技术;
首先介绍一下GCD的三种队列:
- 全局队列:所有添加到该队列的任务都是并发执行的;
- 串行队列:所有添加到串行队列的任务都是顺序执行的;
- 主队列:添加到主队列中的任务都是在主线程执行的;
各队列的获取方法:
全局队列:
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
参数说明:第一个参数是该队列的优先级,建议使用默认,若无特殊要求最好不要随意设置优先级
第二个参数是预留参数,需要填0
串行队列:
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
参数说明:这是一个创建队列的方法,第一个参数是队列名这个可以自己随意,第二个参数有两个值DISPATCH_QUEUE_SERIAL表示创建一个串行队列
DISPATCH_QUEUE_CONCURRENT表示创建一个并行队列(感觉意义不大因为已经有了全局队列)
主队列: dispatch_queue_t queue =dispatch_get_main_queue();
以上就是三种队列的获取方法
下面开始介绍GCD中任务执行方法
GCD任务执行分为同步方法和异步方法,其实实际是同步还是异步需要方法名和执行队列共同来决定的,这就需要读者自己多去练习才能完全理解
首先是异步方法
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
参数:第一个参数为执行队列第二个参数是任务的代码块
同步方法:
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
参数与异步方法传入参数一样
这里由于有两种执行方法,四种队列组合方式实在是太多,我也就不一一列举了,如果想要了解GCD其实最直接的方法就是,分别给两种方法传入不同的队列,然后按照各种顺序调用,只有多练习才能完全掌握;
其实GCD在实际使用中是非常简单的
只需要两步而已:
第一步获取一个执行队列,第二步将操作同步或者异步的加入到执行队列中去
注:示例代码我在找一个比较稳定的网盘,所以会稍后上传