NSOperation 簡介和應用

基本介紹

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]);
    
    
}

打印內容html

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]);

}

打印紀錄ios

 

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設置回默認值,你能夠執行下列操做:app

myQueue.MaxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount; 異步

 

待處理的操做:

任什麼時候候你能夠詢問一個隊列哪一個操做在裏面,而且總共有多少個操做在裏面。記住只有那些等待被執行的操做,還有那些正在運行的操做,會被保留在隊列中。操做一完成,就會退出隊列。 
NSArray *active_and_pending_operations = myQueue.operations;
NSInteger count_of_operations = myQueue.operationCount; async

 

暫停隊列:你能夠經過設定setSuspended:YES來暫停一個隊列。這樣會暫停全部在隊列中的操做 — 你不能單獨的暫停操做。要從新開始隊列,只要簡單的setSuspended:NO。 
// Suspend a queue
[myQueue setSuspended:YES];
.
.
.
// Resume a queue
[myQueue setSuspended: NO]; 

取消操做:要取消一個隊列中的全部操做,你只要簡單的調用「cancelAllOperations」方法便可。還記得以前提醒過常常檢查NSOperation中的isCancelled屬性嗎?atom

 

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

相關文章
相關標籤/搜索