IOS中支持多线程操作,使用NSThread和NSInvocationOperation可以完成多线程功能。多线程的功能主要是为了防止阻塞主线程的工作(主要是UI操作和显示),使一些耗时的的操作在另一个线程中完成,完成后可以通知主线程来进行UI上的更新。多线程功能在实际开发中用的很多,最典型的就是网络请求和处理操作,下面主要来讨论一下Cocoa中的NSThread和NOperation:
一、NSThread
创建NSThread主要有两种方式:
1.使用类方法创建
[NSThread detachNewThreadSelector:@selector(doInBackgroud) toTarget:self withObject:nil];
2.使用传统方式创建
NSThread *thread = [[NSThreadalloc] initWithTarget:self selector:@selector(doInBackgroud) object:nil];
[thread start];
两种方式的区别:
1.第一种方式会立即调用并执行线程,第二种必须调用start方法后才会开始执行线程,在此之前可以对线程进行一些设置,比如线程优先级等。第二种方式与Java中线程的使用类似。
2.使用类方法(Convenient Method)创建的线程不需要进行内存清理,而使用initWithTarget方法创建的线程需要当retainCount为0时调用release方法释放内存
第二 NSOperation
1 怎么样使用NSOperation?
NSOperation 本身是一个抽象类,所以要用它的子类进行创建对象。它的子类有:
1) NSInvocationOperation
2) NSBlockOperation
2 子类的具体使用
NSInvocationOperation
代码片段:
NSInvocationOperation *invocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(loadImage:) object:@"haha"];
invocation.queuePriority = NSOperationQueuePriorityHigh;
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:invocation];
NSBlockOperation
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"cdscdsvdsvvv");
}];
[queue addOperation:block];
NSOperationQueue
NSOperation的start方法默认是同步执行任务,这样的使用并不多见,只有将NSOperation与NSOperationQueue进行结合,才会发挥出这种多线程技术的最大功效.当NSOperation被添加到NSOperationQueue中后,就会全自动地执行异步操作.
NSOperationQueue的种类:
自带主队列[NSOperationQueue mainQueue]: 添加到主队列中的任务都会在主线程中执行 自己创建队列(非主队列)NSOperationQueue *queue = [[NSOperationQueue alloc] init];: 这种队列同时包含串行、并发的功能,添加到非主队列的任务会自动放到子线程中执行
向NSOperationQueue中添加操作:
[queue addOperation:invocation];;
[queue addOperation:block];
设置NSOperationQueue的最大并发数
NSOperationQueue可以通过以下方法设置最大并发数,setMaxConcurrentOperationCount:,值得注意的是:当并发数为1就变成了串行执行任务
NSOperationQueue的暂停恢复和取消
取消
NSOperation有一个cancel方法可以取消单个操作
NSOperationQueue的cancelAllOperations相当于队列中的每个operation调用了cancel方法,会取消队列里面全部的操作.
但是,不能取消正在进行中的任务,队列调用了cancelAllOperations后会等当前正在进行的任务执行完闭后取消后面的操作
挂起和恢复
isSuspended : 判断是否挂起
setSuspended: YES表示挂起,NO表示恢复
和取消功能类似,我们同样不能挂起正在运行中的操作,队列会等当前操作结束后将后面的操作暂停(挂起)
添加依赖和监听
通过设置操作间的依赖,可以确定这些操作的执行顺序如:
[op3 addDependency:op1];
[op3 addDependency:op2];
表示op3会在op1和op2都执行完毕后才执行
添加依赖的时候要注意防止添加循环依赖,此外我们还可以在不同队列的operation之间添加依赖
监听
op.completeBlock可以监听一个操作执行完毕的时刻,这个block里面可以添加一些我们需要执行的操作
这个block里面的操作仍然是在子线程执行,但不一定和被监听的操作在同一个线程
GCD
1 什么是GCD?
GCD全称Grand Central Dispatch
2 GCD 实质是什么?
GCD 实质是C语言级别的多线程处理方式,效率高,功能强大
3 具体代码
//获取系统的串行队列
/*
dispatch_queue_t mainSerialQueue = dispatch_get_main_queue();
dispatch_async(mainSerialQueue, ^{
//NSLog(@"当前线程是%@ 是否是主线程%@",[NSThread currentThread],[[NSThread currentThread]isMainThread] ? @"YES" : @"NO" );
});
//系统自带的并行队列
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(concurrentQueue, ^{
//NSLog(@"当前线程是%@ 是否是主线程%d",[NSThread currentThread],[[NSThread currentThread]isMainThread]);
});
//GCD 创建队列
//参数1:队列的名字
//参数2:什么类型的队列(串行or并行),NULL就是串行
dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
//在队列中添加线程
dispatch_async(queue, ^{
//在子线程中获取数据
NSURL *url = [[NSURL alloc]initWithString:URL_IMAGRZHILIN];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
//在主线程里刷新UI
__block ViewController *vc = self;
dispatch_async(dispatch_get_main_queue(), ^{
vc.imageView.image = image;
});
});
*/
//GCD创建串行队列
/*
dispatch_queue_t serialQueue = dispatch_queue_create("SerialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
for (int i = 0; i < 20; i++) {
NSLog(@"%d****************",i);
}
});
dispatch_async(serialQueue, ^{
for (int i = 0; i < 20; i++) {
NSLog(@"++++++++++++++++%d",i);
}
});
*/
//GCD创建并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 20; i++) {
NSLog(@"%d**************",i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 20; i ++) {
NSLog(@"+++++++++++++++++%d",i);
}
});