多線(xiàn)程編程2 - NSOperation

轉(zhuǎn)自:http://blog.csdn.net/q199109106q/article/details/8565923

一、NSOperation

1.簡(jiǎn)介

NSOperation實(shí)例封裝了需要執(zhí)行的操作和執(zhí)行操作所需的數(shù)據(jù),并且能夠以并發(fā)或非并發(fā)的方式執(zhí)行這個(gè)操作。
NSOperation本身是抽象基類(lèi),因此必須使用它的子類(lèi),使用NSOperation子類(lèi)的方式有2種:

1> Foundation框架提供了兩個(gè)具體子類(lèi)直接供我們使用:NSInvocationOperation和NSBlockOperation

2> 自定義子類(lèi)繼承NSOperation,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法

2.執(zhí)行操作

NSOperation調(diào)用start方法即可開(kāi)始執(zhí)行操作,NSOperation對(duì)象默認(rèn)按同步方式執(zhí)行,也就是在調(diào)用start方法的那個(gè)線(xiàn)程中直接執(zhí)行。NSOperation對(duì)象的isConcurrent方法會(huì)告訴我們這個(gè)操作相對(duì)于調(diào)用start方法的線(xiàn)程,是同步還是異步執(zhí)行。isConcurrent方法默認(rèn)返回NO,表示操作與調(diào)用線(xiàn)程同步執(zhí)行

3.取消操作

operation開(kāi)始執(zhí)行之后, 默認(rèn)會(huì)一直執(zhí)行操作直到完成,我們也可以調(diào)用cancel方法中途取消操作

[operation cancel];  

4.監(jiān)聽(tīng)操作的執(zhí)行

如果我們想在一個(gè)NSOperation執(zhí)行完畢后做一些事情,就調(diào)用NSOperation的setCompletionBlock方法來(lái)設(shè)置想做的事情

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

或者

[operation setCompletionBlock:^() {  
    NSLog(@"執(zhí)行完畢");  
}];  

二、NSInvocationOperation

1.簡(jiǎn)介

基于一個(gè)對(duì)象和selector來(lái)創(chuàng)建操作。如果你已經(jīng)有現(xiàn)有的方法來(lái)執(zhí)行需要的任務(wù),就可以使用這個(gè)類(lèi)

2.創(chuàng)建并執(zhí)行操作

// 這個(gè)操作是:調(diào)用self的run方法  
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];  
// 開(kāi)始執(zhí)行任務(wù)(同步執(zhí)行)  
[operation start];  

三、NSBlockOperation

1.簡(jiǎn)介

能夠并發(fā)地執(zhí)行一個(gè)或多個(gè)block對(duì)象,所有相關(guān)的block都執(zhí)行完之后,操作才算完成

2.創(chuàng)建并執(zhí)行操作

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){  
        NSLog(@"執(zhí)行了一個(gè)新的操作,線(xiàn)程:%@", [NSThread currentThread]);  
}];  
 // 開(kāi)始執(zhí)行任務(wù)(這里還是同步執(zhí)行)  
[operation start];  

3.通過(guò)addExecutionBlock方法添加block操作

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){  
    NSLog(@"執(zhí)行第1次操作,線(xiàn)程:%@", [NSThread currentThread]);  
}];  
  
[operation addExecutionBlock:^() {  
    NSLog(@"又執(zhí)行了1個(gè)新的操作,線(xiàn)程:%@", [NSThread currentThread]);  
}];  
  
[operation addExecutionBlock:^() {  
    NSLog(@"又執(zhí)行了1個(gè)新的操作,線(xiàn)程:%@", [NSThread currentThread]);  
}];  
  
[operation addExecutionBlock:^() {  
    NSLog(@"又執(zhí)行了1個(gè)新的操作,線(xiàn)程:%@", [NSThread currentThread]);  
}];  
  
// 開(kāi)始執(zhí)行任務(wù)  
[operation start];  

打印信息如下:

2013-02-02 21:38:46.102 thread[4602:c07] 又執(zhí)行了1個(gè)新的操作,線(xiàn)程:<NSThread: 0x7121d50>{name = (null), num = 1}  
2013-02-02 21:38:46.102 thread[4602:3f03] 又執(zhí)行了1個(gè)新的操作,線(xiàn)程:<NSThread: 0x742e1d0>{name = (null), num = 5}  
2013-02-02 21:38:46.102 thread[4602:1b03] 執(zhí)行第1次操作,線(xiàn)程:<NSThread: 0x742de50>{name = (null), num = 3}  
2013-02-02 21:38:46.102 thread[4602:1303] 又執(zhí)行了1個(gè)新的操作,線(xiàn)程:<NSThread: 0x7157bf0>{name = (null), num = 4}  

可以看出,這4個(gè)block是并發(fā)執(zhí)行的,也就是在不同線(xiàn)程中執(zhí)行的,num屬性可以看成是線(xiàn)程的id

四、自定義NSOperation

1.簡(jiǎn)介

如果NSInvocationOperation和NSBlockOperation對(duì)象不能滿(mǎn)足需求, 你可以直接繼承NSOperation, 并添加任何你想要的行為。繼承所需的工作量主要取決于你要實(shí)現(xiàn)非并發(fā)還是并發(fā)的NSOperation。定義非并發(fā)的NSOperation要簡(jiǎn)單許多,只需要重載-(void)main這個(gè)方法,在這個(gè)方法里面執(zhí)行主任務(wù),并正確地響應(yīng)取消事件; 對(duì)于并發(fā)NSOperation, 你必須重寫(xiě)NSOperation的多個(gè)基本方法進(jìn)行實(shí)現(xiàn)(這里暫時(shí)先介紹非并發(fā)的NSOperation)

2.非并發(fā)的NSOperation

比如叫做DownloadOperation,用來(lái)下載圖片

1> 繼承NSOperation,重寫(xiě)main方法,執(zhí)行主任務(wù)

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  
  
// 圖片下載的協(xié)議  
@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;  
}  
// 釋放內(nèi)存  
- (void)dealloc {  
    [super dealloc];  
    [_delegate release];  
    [_imageUrl release];  
}  
  
// 執(zhí)行主任務(wù)  
- (void)main {  
    // 新建一個(gè)自動(dòng)釋放池,如果是異步執(zhí)行操作,那么將無(wú)法訪(fǎng)問(wèn)到主線(xiàn)程的自動(dòng)釋放池  
    @autoreleasepool {  
        // ....  
    }  
}  
@end  

2> 正確響應(yīng)取消事件

operation開(kāi)始執(zhí)行之后,會(huì)一直執(zhí)行任務(wù)直到完成,或者顯式地取消操作。取消可能發(fā)生在任何時(shí)候,甚至在operation執(zhí)行之前。盡管NSOperation提供了一個(gè)方法,讓?xiě)?yīng)用取消一個(gè)操作,但是識(shí)別出取消事件則是我們自己的事情。如果operation直接終止, 可能無(wú)法回收所有已分配的內(nèi)存或資源。因此operation對(duì)象需要檢測(cè)取消事件,并優(yōu)雅地退出執(zhí)行
NSOperation對(duì)象需要定期地調(diào)用isCancelled方法檢測(cè)操作是否已經(jīng)被取消,如果返回YES(表示已取消),則立即退出執(zhí)行。不管是自定義NSOperation子類(lèi),還是使用系統(tǒng)提供的兩個(gè)具體子類(lèi),都需要支持取消。isCancelled方法本身非常輕量,可以頻繁地調(diào)用而不產(chǎn)生大的性能損失
以下地方可能需要調(diào)用isCancelled:* 在執(zhí)行任何實(shí)際的工作之前* 在循環(huán)的每次迭代過(guò)程中,如果每個(gè)迭代相對(duì)較長(zhǎng)可能需要調(diào)用多次* 代碼中相對(duì)比較容易中止操作的任何地方
DownloadOperation的main方法實(shí)現(xiàn)如下

- (void)main {  
    // 新建一個(gè)自動(dòng)釋放池,如果是異步執(zhí)行操作,那么將無(wú)法訪(fǎng)問(wèn)到主線(xiàn)程的自動(dòng)釋放池  
    @autoreleasepool {  
        if (self.isCancelled) return;  
          
        // 獲取圖片數(shù)據(jù)  
        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:)]) {  
            // 把圖片數(shù)據(jù)傳回到主線(xiàn)程  
            [(NSObject *)self.delegate performSelectorOnMainThread:@selector(downloadFinishWithImage:) withObject:image waitUntilDone:NO];  
        }  
    }  
}  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容