NSOperation 简介和应用
NSOperation 简介和应用
云飞扬v5 发表于1年前
NSOperation 简介和应用
  • 发表于 1年前
  • 阅读 1
  • 收藏 0
  • 点赞 0
  • 评论 0

基本介绍

NSBlockOperation

 

- (void)singleBlockOperation{
    NSLog(@"thread == %@ 1",[NSThread currentThread]);
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){
         NSLog(@"thread == %@ doing a operation",[NSThread currentThread]);
        
    }];
    // 开始执行任务
    NSLog(@"thread == %@ 2",[NSThread currentThread]);
    
    [operation start];
    
    NSLog(@"thread == %@ after operation",[NSThread currentThread]);
    
    
}

打印内容

2016-11-12 10:17:13.001 MutipleThreadPractice[77168:3862880] thread == <NSThread: 0x7f9451704800>{number = 1, name = main} 1
2016-11-12 10:17:13.002 MutipleThreadPractice[77168:3862880] thread == <NSThread: 0x7f9451704800>{number = 1, name = main} 2
2016-11-12 10:17:13.002 MutipleThreadPractice[77168:3862880] thread == <NSThread: 0x7f9451704800>{number = 1, name = main} doing a operation
2016-11-12 10:17:13.002 MutipleThreadPractice[77168:3862880] thread == <NSThread: 0x7f9451704800>{number = 1, name = main} after operation

 

- (void)multipleBlockOperation{
    
    NSLog(@"thread== %@ start", [NSThread currentThread]);
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){
        NSLog(@"thread== %@ 1", [NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^() {
        NSLog(@"thread== %@ 2", [NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^() {
        NSLog(@"thread== %@ 3", [NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^() {
        NSLog(@"thread== %@ 4", [NSThread currentThread]);
    }];
    
    
    NSLog(@"thread== %@ 5", [NSThread currentThread]);
    // 开始执行任务
    [operation start];
    
    
    NSLog(@"thread== %@ 6", [NSThread currentThread]);

}

打印纪录

 

2016-11-12 10:23:59.998 MutipleThreadPractice[77537:3867741] thread== <NSThread: 0x7fb4f16040c0>{number = 1, name = main} start
2016-11-12 10:23:59.998 MutipleThreadPractice[77537:3867741] thread== <NSThread: 0x7fb4f16040c0>{number = 1, name = main} 5
2016-11-12 10:23:59.998 MutipleThreadPractice[77537:3867741] thread== <NSThread: 0x7fb4f16040c0>{number = 1, name = main} 1
2016-11-12 10:23:59.998 MutipleThreadPractice[77537:3867741] thread== <NSThread: 0x7fb4f16040c0>{number = 1, name = main} 2
2016-11-12 10:23:59.999 MutipleThreadPractice[77537:3867741] thread== <NSThread: 0x7fb4f16040c0>{number = 1, name = main} 4
2016-11-12 10:23:59.999 MutipleThreadPractice[77537:3869224] thread== <NSThread: 0x7fb4f1719040>{number = 4, name = (null)} 3
2016-11-12 10:24:00.001 MutipleThreadPractice[77537:3867741] thread== <NSThread: 0x7fb4f16040c0>{number = 1, name = main} 6

 

取消操作

[operation cancel];

 

NSOperation的依赖关系

MyDownloadOperation *downloadOp = [[MyDownloadOperation alloc] init]; // MyDownloadOperation is a subclass of NSOperation
MyFilterOperation *filterOp = [[MyFilterOperation alloc] init]; // MyFilterOperation  is a subclass of NSOperation
         
[filterOp addDependency:downloadOp];

要删除依赖性:
[filterOp removeDependency:downloadOp];

 

执行完block后进行的操作

    operation.completionBlock = ^() {
        NSLog(@"执行完毕");
    };

 

NSOperationQueue

NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
myQueue.name = @"Download Queue";

并发操作的最大值:

你可以设定NSOperationQueue可以并发运行的最大操作数。NSOperationQueue会选择去运行任何数量的并发操作,但是不会超过最大值。

myQueue.MaxConcurrentOperationCount = 3;

如果你改变了主意,想将MaxConcurrentOperationCount设置回默认值,你可以执行下列操作:

myQueue.MaxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount; 

 

待处理的操作:

任何时候你可以询问一个队列哪个操作在里面,并且总共有多少个操作在里面。记住只有那些等待被执行的操作,还有那些正在运行的操作,会被保留在队列中。操作一完成,就会退出队列。 
NSArray *active_and_pending_operations = myQueue.operations;
NSInteger count_of_operations = myQueue.operationCount; 

 

暂停队列:你可以通过设定setSuspended:YES来暂停一个队列。这样会暂停所有在队列中的操作 — 你不能单独的暂停操作。要重新开始队列,只要简单的setSuspended:NO。 
// Suspend a queue
[myQueue setSuspended:YES];
.
.
.
// Resume a queue
[myQueue setSuspended: NO]; 

取消操作:要取消一个队列中的所有操作,你只要简单的调用“cancelAllOperations”方法即可。还记得之前提醒过经常检查NSOperation中的isCancelled属性吗?

 

UIImage *myImage = nil;
 
// Create a weak reference
__weak UIImage *myImage_weak = myImage;
 
// Add an operation as a block to a queue
[myQueue addOperationWithBlock: ^ {
 
    // a block of operation
    NSURL *aURL = [NSURL URLWithString:@"http://www.somewhere.com/image.png"];
    NSError *error = nil;
    NSData *data = [NSData dataWithContentsOfURL:aURL options:nil error:&error];
    If (!error)
        [myImage_weak imageWithData:data];
 
    // Get hold of main queue (main thread)
    [[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
        myImageView.image = myImage_weak; // updating UI
    }];
 
}]; 

 

 

 

自定义NSOperation

自定义了一个NSOperation的子类,然后重写main方法。并定义了一个代理方法,用来处理Operation执行完毕后的操作。

 

 

app.plist的内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
	<dict>
		<key>icon</key>
		<string>http://zbimg.25pp.com/images/artwork/102/951610982_54x54.jpg</string>
		<key>name</key>
		<string>菜鸟裹裹</string>
		<key>download</key>
		<string></string>
	</dict>
	<dict>
		<key>icon</key>
		<string>http://zbimg.25pp.com/images/artwork/92/855031900_54x54.jpg</string>
		<key>name</key>
		<string>十六番</string>
		<key>download</key>
		<string></string>
	</dict>
	<dict>
		<key>icon</key>
		<string>http://zbimg.25pp.com/images/artwork/246/950137846_54x54.jpg</string>
		<key>name</key>
		<string>暴风魔镜Pro</string>
		<key>download</key>
		<string></string>
	</dict>
	<dict>
		<key>icon</key>
		<string>http://zbimg.25pp.com/images/artwork/189/1044569021_54x54.jpg</string>
		<key>name</key>
		<string>斗图神器</string>
		<key>download</key>
		<string></string>
	</dict>
	<dict>
		<key>icon</key>
		<string>http://zbimg.25pp.com/images/artwork/80/1048881232_54x54.jpg</string>
		<key>name</key>
		<string>糖果工厂</string>
		<key>download</key>
		<string></string>
	</dict>
	<dict>
		<key>icon</key>
		<string>http://zbimg.25pp.com/images/artwork/110/656554606_54x54.jpg</string>
		<key>name</key>
		<string>念力移物</string>
		<key>download</key>
		<string></string>
	</dict>
	<dict>
		<key>icon</key>
		<string>http://zbimg.25pp.com/images/artwork/218/904209370_54x54.jpg</string>
		<key>name</key>
		<string>B612</string>
		<key>download</key>
		<string></string>
	</dict>
</array>
</plist>

 

YYModel.h

#import <Foundation/Foundation.h>

@interface YYappModel : NSObject

/**
 *应用名称
 */
@property(nonatomic,copy)NSString *name;
/**
 *  应用图片
 */
@property(nonatomic,copy)NSString *icon;
/**
 *  应用的下载量
 */
@property(nonatomic,copy)NSString *download;

+(instancetype)appModelWithDict:(NSDictionary *)dict;
-(instancetype)initWithDict:(NSDictionary *)dict;

@end

 

YYModel.m

#import "YYappModel.h"

@implementation YYappModel

-(instancetype)initWithDict:(NSDictionary *)dict
{
    if (self=[super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

//工厂方法
+(instancetype)appModelWithDict:(NSDictionary *)dict
{
    return [[self alloc]initWithDict:dict];
}

@end

 

YYdownLoadOperation.h

#import <Foundation/Foundation.h>
#pragma mark -设置代理和代理方法
@class YYdownLoadOperation;
@protocol YYdownLoadOperationDelegate <NSObject>
- (void)downLoadOperation:(YYdownLoadOperation *)operation
        didFishedDownLoad:(UIImage *)image;

@end

@interface YYdownLoadOperation : NSOperation
@property(nonatomic, copy) NSString *url;
@property(nonatomic, strong) NSIndexPath *indexPath;
@property(nonatomic, strong) id<YYdownLoadOperationDelegate> delegate;
@end

 

YYdownLoadOperation.m

#import "YYdownLoadOperation.h"

@implementation YYdownLoadOperation
-(void)main
{
    NSURL *url=[NSURL URLWithString:self.url];
    NSData *data=[NSData dataWithContentsOfURL:url];
    UIImage *imgae=[UIImage imageWithData:data];
    
    NSLog(@"--%@--",[NSThread currentThread]);
    //图片下载完毕后,通知代理
    if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFishedDownLoad:)]) {
        dispatch_async(dispatch_get_main_queue(), ^{//回到主线程,传递数据给代理对象
            [self.delegate downLoadOperation:self didFishedDownLoad:imgae];
        });
    }
}
@end

 

CustomOperationDemoViewController.h

 

#import <UIKit/UIKit.h>

@interface CustomOperationDemoViewController : UIViewController

@end

 

CustomOperationDemoViewController.m


#import "CustomOperationDemoViewController.h"
#import "YYappModel.h"
#import "YYdownLoadOperation.h"
@interface CustomOperationDemoViewController ()
<YYdownLoadOperationDelegate,UITableViewDataSource,UITableViewDelegate>

@property(nonatomic,strong)NSArray *apps;

@property(nonatomic,strong)NSOperationQueue *queue;

@property (nonatomic,strong) UITableView *tableView;


@property(nonatomic,strong)NSMutableDictionary *operations;
@property(nonatomic,strong)NSMutableDictionary *images;
@end

@implementation CustomOperationDemoViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.view addSubview:self.tableView];
    
    [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
    
    
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(NSArray *)apps
{
    if (_apps==nil) {
        NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
        NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
        
        //字典转模型
        NSMutableArray *array=[NSMutableArray array];
        for (NSDictionary *dict in tempArray) {
            YYappModel *app=[YYappModel appModelWithDict:dict];
            [array addObject:app];
        }
        _apps=array;
    }
    return _apps;
}

-(NSOperationQueue *)queue
{
    if (_queue==Nil) {
        _queue=[[NSOperationQueue alloc]init];
        //设置最大并发数为3
        _queue.maxConcurrentOperationCount=3;
    }
    return _queue;
}

- (NSMutableDictionary *)images{
    if (!_images) {
        _images = [NSMutableDictionary dictionary];
    }
    return _images;

}

- (NSMutableDictionary *)operations{
    if (!_operations) {
        _operations = [NSMutableDictionary dictionary];
    }
    return _operations;

}

- (UITableView *)tableView{
    if(!_tableView){
        _tableView = [[UITableView alloc]init];
        _tableView.dataSource =self;
        _tableView.delegate = self;
    }
    return _tableView;

}

#pragma mark-数据源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.apps.count;
}


-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID=@"ID";
    UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
    if (cell==nil) {
        cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }
    YYappModel *app=self.apps[indexPath.row];
    cell.textLabel.text=app.name;
    cell.detailTextLabel.text=app.download;
    
    //保证一个url对应一个image对象
    UIImage *image=self.images[app.icon];
    if (image) {//缓存中有图片
        cell.imageView.image=image;
    }else       //  缓存中没有图片,得下载
    {
        //先设置一张占位图片
        cell.imageView.image=[UIImage imageNamed:@"57437179_42489b0"];
        YYdownLoadOperation *operation=self.operations[app.icon];
        if (operation) {//正在下载
            //什么都不做
        }else  //当前没有下载,那就创建操作
        {
            operation=[[YYdownLoadOperation alloc]init];
            operation.url=app.icon;
            operation.indexPath=indexPath;
            operation.delegate=self;
            [self.queue addOperation:operation];//异步下载
            self.operations[app.icon]=operation;
        }
    }
    
    
    return cell;
}
-(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
{
    //1.移除执行完毕的操作
    [self.operations removeObjectForKey:operation.url];
    
    //2.将图片放到缓存中
    self.images[operation.url]=image;
    
    //3.刷新表格(只刷新下载的那一行)
    
    [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    NSLog(@"--%d--%@--",operation.indexPath.row,[NSThread currentThread]);
    
}


 

@end

 

 

参考资料

 

iOS开发多线程篇—自定义NSOperation

http://www.cnblogs.com/wendingding/p/3811121.html

 

多线程编程2-NSOperation

http://www.cnblogs.com/mjios/archive/2013/04/19/3029765.html

 

如何使用NSOperations和NSOperationQueues(二)

http://www.cocoachina.com/industry/20121010/4900.html

共有 人打赏支持
粉丝 11
博文 74
码字总数 67465
×
云飞扬v5
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: