1、pthread
void * run(void *param)
{
for (NSInteger i = 0; i<50000; i++) {
NSLog(@"------buttonClick---%zd--%@", i, [NSThread currentThread]);
}
return NULL;
}
- (IBAction)buttonClick:(id)sender {
pthread_t thread;
pthread_create(&thread, NULL, run, NULL);
pthread_t thread2;
pthread_create(&thread2, NULL, run, NULL);
}
2、NSThread(3种创建方式)
-
创建和启动线程
-
其他创建线程的方式
-
主线程相关用法
-
其他用法
-
控制线程的状态
- 线程之间的通信
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self performSelectorInBackground:@selector(download3) withObject:nil];
}
- (void)download3
{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
UIImage *image = [UIImage imageWithData:data];
// 回到主线程,显示图片(方式一)
[self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
//方式二
// [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
//方式三
// [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];
}
3、GCD
将任务添加到队列交给系统去执行,任务的执行分为同步和异步,异步:具备开启线程的能力,同步:不具备开启线程的能力。队列分为串行和并行,串行,一个接一个进行,并发,可以同时进行。
-
同步函数
//参数1:队列
dispatch_sync(queue, ^{
NSLog(@"100-----%@", [NSThread currentThread]);
});
-
异步函数
//参数1:队列
dispatch_async(queue, ^{
NSLog(@"100-----%@", [NSThread currentThread]);
});
-
串行队列
// 参数1:队列名称;参数2:队列的类型(SERIAL:串行,CONCURRENT:并发,NULL:默认串行)
dispatch_queue_t queue = dispatch_queue_create("串行队列1", DISPATCH_QUEUE_SERIAL);
获取主队列(默认就是串行):
// 1.获得主队列(不管是同步函数还是异步函数创建的任务,只要添加到主队列都只会在主线程中执行,不会开启新的线程)
dispatch_queue_t queue = dispatch_get_main_queue();
-
并发队列
// 参数1:队列名称;参数2:队列的类型(SERIAL:串行,CONCURRENT:并发,NULL:默认串行)
dispatch_queue_t queue = dispatch_queue_create("并发队列1", DISPATCH_QUEUE_CONCURRENT);
获取全局队列(默认就是并发):
//全局并发队列的优先级
//#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
//#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
//#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
//#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
//参数1:队列优先级(一般使用default);参数2:暂时无用,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-
barrier屏障
前面的任务执行结束之后barrier才执行,barrier执行完之后它后面的任务才能执行。注意:queue不能为全局并发队列
dispatch_barrier_async(queue, ^{
NSLog(@"----barrier-----%@", [NSThread currentThread]);
});
-
延时执行
//2秒后打印run
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"run-----");
});
-
一次性代码
使用场景:单例
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"------run");
});
-
快速遍历(迭代)
开启多个线程同时进行
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%@---%zd", [NSThread currentThread], index);
});
-
队列组
保证组里面的任务都执行完之后再往下执行。例如:线程1和线程2分别从网上下载1张图片,线程3需要对这两张图片进行合成。(也可以使用barrier函数)
//全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 1、创建一个队列组
#dispatch_group_t group = dispatch_group_create();
// 2.下载图片操作添加到组
//下载图片1
#dispatch_group_async(group, queue, ^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
self.image1 = [UIImage imageWithData:data];
});
//下载图片2
#dispatch_group_async(group, queue, ^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
self.image2 = [UIImage imageWithData:data];
});
// 3.将图片1、图片2合成一张新的图片
#dispatch_group_notify(group, queue, ^{
// 开启新的图形上下文
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
// 绘制图片
[self.image1 drawInRect:CGRectMake(0, 0, 50, 100)];
[self.image2 drawInRect:CGRectMake(50, 0, 50, 100)];
// 取得上下文中的图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 结束上下文
UIGraphicsEndImageContext();
// 回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
// 4.将新图片显示出来
self.imageView.image = image;
});
});
等待循环里多个请求都请求完成:
4、NSOperation
NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类(三种方式:
)
-
NSInvocationOperation(配合队列一起使用才有意义)
- (void)invocationOperation
{
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
//只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
[op start];
}
- (void)run
{
NSLog(@"------%@", [NSThread currentThread]);
}
-
NSBlockOperation
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self blockOperation];
}
- (void)blockOperation
{
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 在主线程
NSLog(@"下载1------%@", [NSThread currentThread]);
}];
// 添加额外的任务(在子线程执行)
[op addExecutionBlock:^{
NSLog(@"下载2------%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"下载3------%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"下载4------%@", [NSThread currentThread]);
}];
[op start];
}
-
任务添加到队列
- (void)operationQueue1
{
// 创建队列(同时具备串行和并发的功能,默认创建方式是并发)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 创建操作(任务)
// 创建NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download2) object:nil];
// 创建NSBlockOperation
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download4 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download5 --- %@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download6 --- %@", [NSThread currentThread]);
}];
// 创建XMGOperation
XMGOperation *op5 = [[XMGOperation alloc] init];
// 添加任务到队列中,只要添加到队列中,系统会自动帮我们调用任务的start
[queue addOperation:op1]; // [op1 start]
[queue addOperation:op2]; // [op2 start]
[queue addOperation:op3]; // [op3 start]
[queue addOperation:op4]; // [op4 start]
[queue addOperation:op5]; // [op5 start](自定义的队列需要在.m文件里重写main函数)
//也可以不用手动添加任务,直接添加一个block,内部会自动创建并添加
[queue addOperationWithBlock:^{
NSLog(@"download2 --- %@", [NSThread currentThread]);
}];
}
#import "XMGOperation.h"
@implementation XMGOperation
/**
* 需要执行的任务
*/
- (void)main
{
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download1 -%zd-- %@", i, [NSThread currentThread]);
}
//建议执行一段比较耗时的操作后,添加取消判断。否则,外面在调用取消操作的时候,并不能取消这里的任务)
if (self.isCancelled) return;
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download2 -%zd-- %@", i, [NSThread currentThread]);
}
if (self.isCancelled) return;
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download3 -%zd-- %@", i, [NSThread currentThread]);
}
if (self.isCancelled) return;
}
@end
-
其他方法
//设置最大并发数
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
//取消队列的所有操作
- (void)cancelAllOperations;
//提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
//暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
//NSOperation之间可以设置依赖来保证执行顺序
//比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA]; // 操作B依赖于操作A
//可以监听一个操作的执行完毕(监听完成之后所执行的任务不一定和之前操作执行的线程相同,但是是在子线程)
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block;
-
线程之间的通信
下载图片
- (void)test
{
[[[NSOperationQueue alloc] init] addOperationWithBlock:^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
UIImage *image = [UIImage imageWithData:data];
// 回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
}
合成图片
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//防止block操作还没完成image1这个局部变量就销毁了
__block UIImage *image1 = nil;
// 下载图片1
NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
image1 = [UIImage imageWithData:data];
}];
__block UIImage *image2 = nil;
// 下载图片2
NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
image2 = [UIImage imageWithData:data];
}];
// 合成图片
NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{
// 开启新的图形上下文
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
// 绘制图片
[image1 drawInRect:CGRectMake(0, 0, 50, 100)];
image1 = nil;
[image2 drawInRect:CGRectMake(50, 0, 50, 100)];
image2 = nil;
// 取得上下文中的图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 结束上下文
UIGraphicsEndImageContext();
// 回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
//添加依赖保证图片先下载完成
[combine addDependency:download1];
[combine addDependency:download2];
[queue addOperation:download1];
[queue addOperation:download2];
[queue addOperation:combine];
}