首页 > 移动平台 > 详细

iOS多线程-NSOperation简单语法

时间:2016-01-12 16:54:50      阅读:291      评论:0      收藏:0      [点我收藏+]
1> 封装操作

NSInvocationOperation

NSBlockOperation

2> NSOperationQueue

1 主队列 通过mainQueue获得,凡是放到主队列中的任务都将在主线程执行

2  非主队列 直接alloc init出来的队列。非主队列同时具备了并发和串行的功能,通过设置最大并发数属性来控制任务是并发执行还是串行执行,默认是并发

3> 步骤:
//封装操作  
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
//创建队列  
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//把操作添加到队列中  
[queue addOperation:op1];
4> 其他方法:
//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(@“---");

     };
5> NSThread线程间通信
技术分享
 
6> 多图下载问题
出现的问题:
   1)重复下载(内存缓存)—>磁盘缓存
   2)UI不流畅(开子线程去下载图片)
      1.图片不显示(刷新指定行)
      2.重复下载(设置操作缓存)
      3.数据错乱(设置占位图片)
设置图片的逻辑:
    //查看该图片在缓存中是否存在,如果存在那么就直接设置,否则查看沙盒是否存在
    //如果存在,直接设置图片&保存一份到内存
    //如果不存在,就去下载,再保存到内存以及沙盒
      (如果plist文件中图片的路径是错的话会导致程序崩溃,所以应该对获得的图片进行判断,如果图片为nil,那么直接return,但在return之前必须移除该图片的下载的队列,表示下载失败之后就不会再添加在下载队列中不再下载)
#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;
}

 

7> 计算代码段执行的时间
//第一种方法 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。
3.在使用栅栏函数的时候,苹果官方明确规定栅栏函数只有在和使用create函数自己的创建的并发队列一起使用的时候才有效

iOS多线程-NSOperation简单语法

原文:http://www.cnblogs.com/liugengqun/p/5124830.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!