NSInvocationOperation
NSBlockOperation
1 主队列 通过mainQueue获得,凡是放到主队列中的任务都将在主线程执行
2 非主队列 直接alloc init出来的队列。非主队列同时具备了并发和串行的功能,通过设置最大并发数属性来控制任务是并发执行还是串行执行,默认是并发
//封装操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
//创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//把操作添加到队列中
[queue addOperation:op1];
//1)封装操作2)把操作添加到队列中
[queue addOperationWithBlock:^{
NSLog(@"7----%@",[NSThreadcurrentThread]);
}];
//追加任务 如果内部的操作数量大于1,那么就会开子线程异步执行
[op3 addExecutionBlock:^{
NSLog(@"4----%@",[NSThread currentThread]);
}];
//最大并发数设置
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
/*
暂停 suspended
suspended设置为YES表示暂停 暂停表示不继续执行队列中的下一个任务,暂停操作是可以恢复的
取消 cancelAllOperations
取消队列里面的所有操作,取消之后,当前正在执行的操作的下一个操作将不再执行,而且永远都不在执行,就像后面的所有任务都从队列里面移除了一样,取消操作是不可以恢复的
[self.queue cancelAllOperations];
*/
//自定义NSOperation(XMGOperation)取消操作 GQOperation下的main函数:(main函数是说明执行的是哪些操作)
-(void)main
{
//耗时操作1
for (int i = 0; i<1000; i++) {
NSLog(@"任务1-%d--%@",i,[NSThread currentThread]);
}
//苹果官方建议,每当执行完一次耗时操作之后,就查看一下当前队列是否为取消状态,如果是,那么就直接退出
//好处是可以提高程序的性能
if (self.isCancelled) {
return;
}
//耗时操作2
for (int i = 0; i<1000; i++) {
NSLog(@"任务1-%d--%@",i,[NSThread currentThread]);
}
}
//设置依赖 addDependency
[operationB addDependency:operationA]; // 操作B依赖于操作A 而且可以跨队列依赖
//completionBlock 某操作完成后再执行的操作
op4.completionBlock = ^{ //op4操作完才执行如下代码块
NSLog(@“---");
};
#import "ViewController.h"
#import "appItem.h"
@interface ViewController ()
//保存app模型数组
@property (nonatomic, strong) NSMutableArray *appArr;
//内存缓存
@property (nonatomic, strong) NSMutableDictionary *imageDict;
//队列数组
@property (nonatomic, strong) NSMutableDictionary *operationDict;
@end
@implementation ViewController
- (NSMutableDictionary *)imageDict{
if (_imageDict == nil) {
_imageDict = [NSMutableDictionary dictionary];
}
return _imageDict;
}
- (NSMutableDictionary *)operationDict{
if (_operationDict == nil) {
_operationDict = [NSMutableDictionary dictionary];
}
return _operationDict;
}
- (NSMutableArray *)appArr{
if (_appArr == nil) {
NSMutableArray *models = [NSMutableArray array];
NSString *str = [[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil];
NSArray *arrDict = [NSArray arrayWithContentsOfFile:str];
for (NSDictionary *dict in arrDict) {
appItem *app = [appItem appItemWithDict:dict];
[models addObject:app];
}
_appArr = [models copy];
}
return _appArr;
}
#pragma mark - 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.appArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ID = @"app";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
appItem *app = self.appArr[indexPath.row];
cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download;
//从内存中去
UIImage *image = [self.imageDict objectForKey:app.icon];
if (image) { //如果图片存在内存中
cell.imageView.image = image;
NSLog(@"内存中取%i",indexPath.row);
}else{
NSData *data = [NSData dataWithContentsOfFile:[self getFullPath:app.icon]];
data = nil;
if (data) { //如果图片存在沙盒中
//沙盒的图片数据转换成图片
UIImage *image = [UIImage imageWithData:data];
cell.imageView.image = image;
//保存一份到内存
[self.imageDict setObject:image forKey:app.icon];
}else{
//下载的时候还没下载完用占位图片显示
cell.imageView.image = [UIImage imageNamed:@"屏幕快照"];
//取出操作
NSOperation *operation = [self.operationDict objectForKey:app.icon];
if (operation) { //已有下载操作
//什么都不干
NSLog(@"%i已在下载", indexPath.row);
}else{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
UIImage *image = [UIImage imageWithData:data];
cell.imageView.image = image;
//如果图片的链接是错的情况
if (image == nil) {
//取消队列中的操作
[self.operationDict removeObjectForKey:app.icon];
return;
}
//保存到内存中
[self.imageDict setObject:image forKey:app.icon];
//保存到沙盒
NSString *fullPath = [self getFullPath:app.icon];
//写入
[data writeToFile:fullPath atomically:YES];
NSLog(@"下载%i",indexPath.row);
//回到主线程刷新ui
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}];
//下载完毕后要移除下载操作
[self.operationDict removeObjectForKey:app.icon];
}];
[queue addOperation:operation];
//保存操作进队列数组
[self.operationDict setObject:operation forKey:app.icon];
}
}
}
return cell;
}
//获得全路径
- (NSString *)getFullPath:(NSString *)urlName{
NSString *cache = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
//获得文件名称
NSString *name = [urlName lastPathComponent];
//拼接文件全路径
NSString *fullPath = [cache stringByAppendingPathComponent:name];
return fullPath;
}
//第一种方法 NSDate
NSDate *start = [NSDate date];
NSData *data = [NSData dataWithContentsOfURL:url];
NSDate *end = [NSDate date];
NSLog(@"第二步操作花费的时间为%f",[end timeIntervalSinceDate:start]);
//第二种方法 CFTimeInterval
CFTimeInterval start = CFAbsoluteTimeGetCurrent();
NSData *data = [NSData dataWithContentsOfURL:url];
CFTimeInterval end = CFAbsoluteTimeGetCurrent();
NSLog(@"第二步操作花费的时间为%f",end - start);
8>使用Crearte函数创建的并发队列和全局并发队列的主要区别:
1.全局并发队列在整个应用程序中本身是默认存在的,并且对应有高优先级、默认优先级、低优先级和后台优先级一共四个并发队列,我们只是选择其中的一个直接拿来用。而Crearte函数是实打实的从头开始去创建一个队列。
2.在iOS6.0之前,在GCD中凡是使用了带Crearte和retain的函数在最后都需要做一次release操作。而主队列和全局并发队列不需要我们手动release。当然了,在iOS6.0之后GCD已经被纳入到了ARC的内存管理范畴中,即便是使用retain或者create函数创建的对象也不再需要开发人员手动释放,我们像对待普通OC对象一样对待GCD就OK。
原文:http://www.cnblogs.com/liugengqun/p/5124830.html