主线程处理UI,避免耗时操作
iOS多线程技术有4种
pthread,通用技术,跨平台 c语言,程序员管理生命周期,几乎不用
NSThread 面向对象,可以直接操作线程 OC语言 程序员 管理生命周期,偶尔使用
GCD 替代NSThread,可以利用多核性能 c语言 自动管理 经常使用
NSOperation 基于GCD,更加面向对象,多了功能 OC语言 自动管理 经常使用
获得主队列
// 1.获得主队列 dispatch_queue_t queue = dispatch_get_main_queue();
获得全局并发队列
// 1.获得全局的并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
GCD其他用法
dispatch_once
dispatch_after
dispatch_group_async\dispatch_group_notify
异步函数,串行队列
/** * 用dispatch_async异步函数往串行队列中添加任务 */ - (void)asyncSerialQueue { // 1.创建串行队列 dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL); // 2.添加任务到队列中 执行 dispatch_async(queue, ^{ NSLog(@"----下载图片1-----%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"----下载图片2-----%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"----下载图片3-----%@", [NSThread currentThread]); }); // 总结: 只开1个线程执行任务 }
异步函数,并发队列
/** * 用dispatch_sync同步函数往并发队列中添加任务 */ - (void)syncGlobalQueue { // 1.获得全局的并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 2.添加任务到队列中 执行 dispatch_sync(queue, ^{ NSLog(@"----下载图片1-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"----下载图片2-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"----下载图片3-----%@", [NSThread currentThread]); }); // 总结: 不会开启新的线程, 并发队列失去了并发的功能 }
同步函数,串行队列
/** * 用dispatch_sync同步函数往串行列中添加任务 */ - (void)syncSerialQueue { // 1.创建串行队列 dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL); // 2.添加任务到队列中 执行 dispatch_sync(queue, ^{ NSLog(@"----下载图片1-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"----下载图片2-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"----下载图片3-----%@", [NSThread currentThread]); }); // 3.释放资源 // dispatch_release(queue); // MRC(非ARC) // 总结: 不会开启新的线程 }
同步函数,串行队列
/** * 用dispatch_sync同步函数往串行列中添加任务 */ - (void)syncSerialQueue { // 1.创建串行队列 dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL); // 2.添加任务到队列中 执行 dispatch_sync(queue, ^{ NSLog(@"----下载图片1-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"----下载图片2-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"----下载图片3-----%@", [NSThread currentThread]); }); // 总结: 不会开启新的线程 }
GCD一个例子
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSLog(@"--download--%@", [NSThread currentThread]); // 下载图片 NSURL *url = [NSURL URLWithString:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; // 这行会比较耗时 UIImage *image = [UIImage imageWithData:data]; // 回到主线程显示图片 dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"--imageView--%@", [NSThread currentThread]); self.imageView.image = image; }); });
GCD多个任务构建一个组
完成2个图片的下载以后,进行合并处理
//定义宏简化调用 #define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) #define main_queue dispatch_get_main_queue() // 创建一个组 dispatch_group_t group = dispatch_group_create(); // 开启一个任务下载图片1 __block UIImage *image1 = nil; dispatch_group_async(group, global_queue, ^{ image1 = [self imageWithURL:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"]; }); // 开启一个任务下载图片2 __block UIImage *image2 = nil; dispatch_group_async(group, global_queue, ^{ image2 = [self imageWithURL:@"http://news.baidu.com/z/resource/r/image/2014-06-22/b2a9cfc88b7a56cfa59b8d09208fa1fb.jpg"]; }); // 同时执行下载图片1\下载图片2操作 // 等group中的所有任务都执行完毕, 再回到主线程执行其他操作 dispatch_group_notify(group, main_queue, ^{ self.imageView1.image = image1; self.imageView2.image = image2; // 合并 UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0); [image1 drawInRect:CGRectMake(0, 0, 100, 100)]; [image2 drawInRect:CGRectMake(100, 0, 100, 100)]; self.bigImageView.image = UIGraphicsGetImageFromCurrentImageContext(); // 关闭上下文 UIGraphicsEndImageContext(); });
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil]; self.thread.name = @"线程A"; [self.thread start];
[self performSelectorInBackground:@selector(download) withObject:nil];
下面选一个就行了
// 2.回到主线程显示图片 [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO]; // setImage: 1s [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
解决多个线程同时改变同一个变量的时候的资源抢夺问题,然后变量的数值会不正确
@synchronized
- (void)viewDidLoad { [super viewDidLoad]; // 默认有100张 self.leftTicketsCount = 100; // 开启多条线程同时卖票 self.thread0 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; self.thread0.name = @"售票员 A"; // self.thread0.threadPriority = 0.0; self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; self.thread1.name = @"售票员 B"; // self.thread1.threadPriority = 1.0; self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; self.thread2.name = @"售票员 C"; // self.thread2.threadPriority = 0.0; } /** * 卖票 */ - (void)saleTicket { while (1) { @synchronized(self) { // 加锁(只能用一把锁) // 1.先检查票数 int count = self.leftTicketsCount; if (count > 0) { // 暂停 // [NSThread sleepForTimeInterval:0.0002]; // 2.票数 - 1 self.leftTicketsCount = count - 1; NSThread *current = [NSThread currentThread]; NSLog(@"%@ 卖了一张票, 剩余%d张票", current.name, self.leftTicketsCount); } else { // 退出线程 [NSThread exit]; } } // 解锁 } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.thread0 start]; [self.thread1 start]; [self.thread2 start]; }
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil]; NSBlockOperation *operation2 = [[NSBlockOperation alloc] init]; [operation2 addExecutionBlock:^{ NSLog(@"NSBlockOperation------下载图片1---%@", [NSThread currentThread]); }]; NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 10; i++) { NSLog(@"NSBlockOperation------下载图片---%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:0.1]; } }];
// 2.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 2; // 2 ~ 3为宜 // 设置依赖 [operation2 addDependency:operation3]; [operation3 addDependency:operation1]; // 3.添加操作到队列中(自动执行操作, 自动开启线程) [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3];
//头文件设计 #import <Foundation/Foundation.h> @class HMDownloadOperation; //设置代理 @protocol HMDownloadOperationDelegate <NSObject> @optional - (void)downloadOperation:(HMDownloadOperation *)operation didFinishDownload:(UIImage *)image; @end @interface HMDownloadOperation : NSOperation @property (nonatomic, copy) NSString *url; @property (nonatomic, strong) NSIndexPath *indexPath; @property (nonatomic, weak) id<HMDownloadOperationDelegate> delegate; @end
实现文件
主要需要实现main方法,然后在主线程中将处理结果返回给代理
#import "HMDownloadOperation.h" @implementation HMDownloadOperation /** * 在main方法中实现具体操作 */ - (void)main { @autoreleasepool { NSURL *downloadUrl = [NSURL URLWithString:self.url]; NSData *data = [NSData dataWithContentsOfURL:downloadUrl]; // 这行会比较耗时 UIImage *image = [UIImage imageWithData:data]; if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) { dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程, 传递图片数据给代理对象 [self.delegate downloadOperation:self didFinishDownload:image]; }); } } } @end