在我们做的项目中,这些线程间的通讯多用于图片的下载,而这些常常SDWebImage或者YYWebImage 都会给我们做好,所以我写的并无卵用,
- 下面来总结一下线程间通信的几种方法 :
- NSThread
- GCD
- NSOperation
- NSthread:
优点:比其他两种轻量级。
缺点:需要自己管理线程的生命周期,线程同步。 线程同步对数据的加锁会有一定的开销。
-
Operation、GCD:
优点:不需要关心线程管理,数据同步的事情。
两者区别:NSOperationQueue可以方便的管理并发、 NSOperation之间的优先级。GCD主要与block结合使用。代码简洁高效
- 性能:GCD更接近底层,而NSOperationQueue则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的。这取决于使用Instruments进行代码性能分析,如有必要的话
- 从异步操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现,而NSOperationQueue已经内建了这些支持
- 如果异步操作的过程需要更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势
<h3>☆分别用这三个方法创建一个下载图片的案例
NSThread
- (void)thread{
//1.去网络上加载数据
NSString *imageURLString = @"http://imgsrc.baidu.com/forum/w%3D580/sign=13eeace7d058ccbf1bbcb53229d9bcd4/9245d688d43f879404f24d7bd31b0ef41bd53a51.jpg";
[self performSelectorInBackground:@selector(loadImage:) withObject:imageURLString];//
}
- (void)loadImage:(NSString *)imageURLString{
NSLog(@"loadImage--- %@",[NSThread currentThread]);
//1.拿着imageURLString去网络上下载
NSURL *url = [NSURL URLWithString:imageURLString];
//2.去网络上加载图片
NSData *imageData = [NSData dataWithContentsOfURL:url];
//3.将我们从网络上获取到的图片的二进制,转成UIImage
UIImage *image = [UIImage imageWithData:imageData];
//4.回到主线程,并且将image传给主线程,让主线程去更新UI
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];//YES同步,NO 异步
NSLog(@"---子线程over---");
}
- (void)updateUI:(UIImage *)image{
NSLog(@"updateUI---%@",[NSThread currentThread]);
self.imageView.image = image;
}
GCD
- (void)gcd{
NSString *imageURLString = @"http://imgsrc.baidu.com/forum/w%3D580/sign=13eeace7d058ccbf1bbcb53229d9bcd4/9245d688d43f879404f24d7bd31b0ef41bd53a51.jpg";
//1.去子线程,下载图片,这是一个耗时间的操作
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"gcd---loadImage===%@",[NSThread currentThread]);
//1.1.拿着imageURLString去网络上下载
NSURL *url = [NSURL URLWithString:imageURLString];
//1.2.去网络上加载图片
NSData *imageData = [NSData dataWithContentsOfURL:url];
//1.3.将我们从网络上获取到的图片的二进制,转成UIImage
UIImage *image = [UIImage imageWithData:imageData];
//2.回到主线程更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"updateUI---%@",[NSThread currentThread]);
weakSelf.imageView.image = image;
});
});
//2.回到主线程更新UI
}
☆NSOperation (SDWebImage或者YYWebImage)都是这样实现的
NSOperation 有两个子类(不好使),但通常是用第三种方法实现
1> NSInvocationOperation
2> NSBlockOperation
3> 自定义子类继承NSOperation,实现内部相应的方法
- 创建一个继承 NSOperation 的类
- 创建一个下载任务器,创建一个队列,任务添加队列,这时会执行自定义operation类里的 main 方法
- 在任务器中异步下载图片
- 返回主线程跟新UI
- (void)operation{
//1.自定义一个下载的任务
__weak typeof(self) weakSelf = self;
DownLoadOperation *downLoadOp = [[DownLoadOperation alloc] init];
downLoadOp.imageURLString = @"http://e.hiphotos.bdimg.com/album/pic/item/9345d688d43f8794f0ab07ddd01b0ef41ad53ae8.jpg";
downLoadOp.finshedBlock = ^(UIImage *image){
//NSLog(@"%@---%@",image,[NSThread currentThread]);
//2.回到主线程更新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//在主线程
weakSelf.imageView.image = image;
}];
};
//2.队列
NSOperationQueue *concurrentQueue = [[NSOperationQueue alloc] init];
//3.将我们的任务,添加到队列中,然后队列就会调度downLoadOp,去调用downLoadOp它的main
[concurrentQueue addOperation:downLoadOp];
}
下载容器
#import <UIKit/UIKit.h>
//typedef int MyInt;
//一般建议首字母大写
typedef void(^FinishedBlock)(UIImage *image);
@interface DownLoadOperation : NSOperation
// 图片url地址
@property (nonatomic , copy) NSString *imageURLString;
// 回调的block
@property (nonatomic , copy) FinishedBlock finshedBlock;
@end
#import "DownLoadOperation.h"
@implementation DownLoadOperation
- (void)main{
//因为我们的每一个线程在使用过程中,都会产生对象,当我们线程结束的时候,需要对我们在该线程中使用过的对象,做release
@autoreleasepool {
NSLog(@"---main----%@",[NSThread currentThread]);
//1.1.拿着imageURLString去网络上下载
NSURL *url = [NSURL URLWithString:self.imageURLString];
//1.2.去网络上加载图片
NSData *imageData = [NSData dataWithContentsOfURL:url];
//1.3.将我们从网络上获取到的图片的二进制,转成UIImage
UIImage *image = [UIImage imageWithData:imageData];
//2.这个时候通过block将我们的image,传给控制器
if (self.finshedBlock) {
self.finshedBlock(image);
}
}
}
@end