iOS多線程系列(二)------NSOperation

轉載自:http://blog.csdn.net/q199109106q/article/details/8565923,尊重原創!併發

 

NSOperation 是抽象類,對它的使用能夠直接使用系統提供的兩個子類:NSInvocationOperation、NSBlockOperation,也能夠本身寫個類,繼承NSOperation。異步

1、NSInvocationOperation函數

基於一個對象和selector來建立操做。若是你已經有現有的方法來執行須要的任務,就可使用這個類性能

(1)初始化atom

NSOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(testApply) object:nil];
NSOperation *operation2 = [[NSInvocationOperation alloc]initWithInvocation:<#(NSInvocation *)#>];
[operation1 start];  //開始執行,同步

 

2、NSBlockOperationurl

可以併發地執行一個或多個block對象,全部相關的block都執行完以後,操做纔算完成spa

(1)建立並執行添加任務.net

//建立隊列
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"第一個,線程id:%@", [NSThread currentThread]); }];
//添加任務 [operation addExecutionBlock:
^() { NSLog(@"第二個,線程id:%@", [NSThread currentThread]); }]; [operation addExecutionBlock:^() { NSLog(@"第三個,線程id:%@", [NSThread currentThread]); }]; [operation addExecutionBlock:^() { NSLog(@"第四個,線程id:%@", [NSThread currentThread]); }]; // 開始執行任務(這裏仍是同步執行) [operation start];

打印信息以下:線程

2014-11-06 21:07:56.169 DispatchTest[16828:481571] 第三個,線程id:<NSThread: 0x7fe959638780>{number = 3, name = (null)}
2014-11-06 21:07:56.169 DispatchTest[16828:481491] 第一個,線程id:<NSThread: 0x7fe959613220>{number = 1, name = main}
2014-11-06 21:07:56.169 DispatchTest[16828:481570] 第四個,線程id:<NSThread: 0x7fe959638a00>{number = 4, name = (null)}
2014-11-06 21:07:56.169 DispatchTest[16828:481569] 第二個,線程id:<NSThread: 0x7fe95956c200>{number = 2, name = (null)}

根據number能夠看出,這幾個任務並非在同一線程被執行的,說明他們是併發執行的,且執行順序和加入隊列的順序沒有關係。代理

 

(2)取消操做

operation開始執行以後, 默認會一直執行操做直到完成,咱們也能夠調用cancel方法中途取消操做

[operation cancel];  

 

(3)監聽操做的執行

若是咱們想在一個NSOperation執行完畢後作一些事情,就調用NSOperation的setCompletionBlock方法來設置想作的事情

operation.completionBlock = ^() {  
    NSLog(@"執行完畢");  
}; 

 

3、本身寫類繼承NSOperation

工做量取決於你但願你的NSOperation是併發仍是非併發。

非併發:只須要重載-(void)main這個方法,在這個方法裏面執行主任務,並正確地響應取消事件

併發: 須要重載以下4個方法          

 - (void)start                      //執行任務主函數,線程運行的入口函數 
 - (BOOL)isConcurrent          //是否容許併發,返回YES,容許併發,返回NO不容許。默認返回NO ,便是同步的
 - (BOOL)isExecuting            
 - (BOOL)isFinished             //是否已經完成,這個必需要重載,否則放在放在NSOperationQueue裏的NSOpertaion不能正常釋放   

 

非併發示例:一個圖片下載的類好比叫作DownloadOperation,用來下載圖片

1> 繼承NSOperation,重寫main方法,執行主任務

 

DownloadOperation.h

#import <Foundation/Foundation.h>
@protocol DownloadOperationDelegate;

@interface DownloadOperation : NSOperation
// 圖片的url路徑
@property (nonatomic, copy) NSString *imageUrl;
// 代理
@property (nonatomic, retain) id<DownloadOperationDelegate> delegate;

- (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate;
@end

// 圖片下載的協議
@protocol DownloadOperationDelegate <NSObject>
- (void)downloadFinishWithImage:(UIImage *)image;
@end

 

DownloadOperation.m

#import "DownloadOperation.h"

@implementation DownloadOperation
@synthesize delegate = _delegate;
@synthesize imageUrl = _imageUrl;

// 初始化
- (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate {
    if (self = [super init]) {
        self.imageUrl = url;
        self.delegate = delegate;
    }
    return self;
}
// 釋放內存
- (void)dealloc {
    [super dealloc];
    [_delegate release];
    [_imageUrl release];
}

// 執行主任務
- (void)main {
    // 新建一個自動釋放池,若是是異步執行操做,那麼將沒法訪問到主線程的自動釋放池
    @autoreleasepool {
        // ....
    }
}
@end

 

2> 正確響應取消事件

operation開始執行以後,會一直執行任務直到完成,或者顯式地取消操做。

取消可能發生在任什麼時候候,甚至在operation執行以前。儘管NSOperation提供了一個方法,讓應用取消一個操做,可是識別出取消事件則是咱們本身的事情。

若是operation直接終止, 可能沒法回收全部已分配的內存或資源。所以operation對象須要檢測取消事件,並優雅地退出執行

NSOperation對象須要按期地調用isCancelled方法檢測操做是否已經被取消,若是返回YES(表示已取消),則當即退出執行。

不論是自定義NSOperation子類,仍是使用系統提供的兩個具體子類,都須要支持取消。

isCancelled方法自己很是輕量,能夠頻繁地調用而不產生大的性能損失

如下地方可能須要調用isCancelled:

  * 在執行任何實際的工做以前

  * 在循環的每次迭代過程當中,若是每一個迭代相對較長可能須要調用屢次

  * 代碼中相對比較容易停止操做的任何地方

 

DownloadOperation的main方法實現以下:

- (void)main {
    // 新建一個自動釋放池,若是是異步執行操做,那麼將沒法訪問到主線程的自動釋放池
    @autoreleasepool {
        if (self.isCancelled) return;
        
        // 獲取圖片數據
        NSURL *url = [NSURL URLWithString:self.imageUrl];
        NSData *imageData = [NSData dataWithContentsOfURL:url];
        
        if (self.isCancelled) {
            url = nil;
            imageData = nil;
            return;
        }
        
        // 初始化圖片
        UIImage *image = [UIImage imageWithData:imageData];
        
        if (self.isCancelled) {
            image = nil;
            return;
        }
        
        if ([self.delegate respondsToSelector:@selector(downloadFinishWithImage:)]) {
            // 把圖片數據傳回到主線程
            [(NSObject *)self.delegate performSelectorOnMainThread:@selector(downloadFinishWithImage:) withObject:image waitUntilDone:NO];
        }
    }
}
相關文章
相關標籤/搜索