iOS開發之多線程技術——NSOperation篇,iosnsoperation

來源:互聯網
上載者:User

iOS開發之多線程技術——NSOperation篇,iosnsoperation

本篇將從四個方面對iOS開發中使用到的NSOperation技術進行講解:

一、什麼是NSOperation二、我們為什麼使用NSOperation三、在實際開發中如何使用NSOperation  1、自訂NSOperation  2、NSOperation的基本使用  3、NSOperation實現線程間通訊

    1)利用代理進行訊息傳遞

    2)利用通知實現訊息傳遞

    3)利用block進行訊息傳遞

四、與GCD比較一、什麼是NSOperation

  NSOperation是一個抽象的基類,表示一個獨立的計算單元,可以為子類提供有用且安全執行緒的建立狀態,優先順序,依賴和取消等操作。系統已經給我們封裝了NSBlockOperation和NSInvocationOperation這兩個實體類。使用起來也非常簡單,不過我們更多的使用是自己繼承並定製自己的操作。

 

二、我們為什麼使用NSOperation

  在iOS開發中,為了提升使用者體驗,我們通常會將操作耗時的操作放在主線程之外的線程進行處理。對於正常的簡單操作,我們更多的是選擇代碼更少的GCD,讓我們專註於自己的商務邏輯開發。NSOperation在ios4後也基於GCD實現,但是相對於GCD來說可控性更強,並且可以加入操作依賴。 

 

三、在實際開發中如何使用NSOperation1、自訂NSOperation

在實際開發中,系統提供的NSOperation可能無法滿足我們的需求,這時,我們就需要自訂我們自己的NSOperation

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIImageView *imageView;@end@implementation ViewController- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {        NSLog(@"touchesBegan------%@", [NSThread currentThread]);        if (!self.imageView.image) {  // 避免重複下載,增強使用者體驗                NSOperationQueue *queue = [[NSOperationQueue alloc] init];        [queue setMaxConcurrentOperationCount:6];                MyOperation *myO = [[MyOperation alloc] init];        myO.imageView = self.imageView;        [queue addOperation:myO];            }        NSLog(@"end");}// 自訂NSOperation@interface MyOperation : NSOperation@property (nonatomic, strong) UIImageView *imageView;@end// 實現自訂NSOperation@implementation MyOperation- (void)main {        NSLog(@"%s----%@", __func__, [NSThread currentThread]);        UIImage *image = [self downLoadImage:@"http://g.hiphotos.baidu.com/image/pic/item/f31fbe096b63f624cd2991e98344ebf81b4ca3e0.jpg"];        dispatch_async(dispatch_get_main_queue(), ^{        NSLog(@"%@======%@", image, [NSThread currentThread]);        self.imageView.image = image;    });}- (UIImage *)downLoadImage:(NSString *)urlString {    NSLog(@"%s----%@",__func__, [NSThread currentThread]);        NSURL *url = [NSURL URLWithString:urlString];    NSData *data = [NSData dataWithContentsOfURL:url];    UIImage *image = [UIImage imageWithData:data];        NSLog(@"圖片下載完成");        return image;}@end

 

 

2、NSOperation的基本使用
#pragma mark#pragma mark - NSOperation進階操作1- (void)highLevelTest1 {    /**     NSOperation 相對於 GCD 來說,增加了以下管理線程的功能:     1.NSOperation可以添加操作依賴:保證操作的執行順序! --> 和GCD中將任務添加到一個串列隊列中是一樣的!一個串列隊列會對應一條線程     GCD 中的按順序執行(串列隊列) ---> 串列執行     添加操作依賴之後,系統有可能串列執行保證任務的執行順序,還有可能綠色線程同步技術,保證任務執行順序     */        NSInvocationOperation *inO = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil];        NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"block1======%@", [NSThread currentThread]);    }];        NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"block2======%@", [NSThread currentThread]);    }];        NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"block3======%@", [NSThread currentThread]);    }];        /**     四個操作都是耗時操作,並且要求按順序執行,操作2是UI操作     添加操作依賴的注意點     1.一定要在將操作添加到操作隊列中之前添加操作依賴     2.不要添加循環相依性     優點:對於不同操作隊列中的操作,操作依賴依然有效     */        // 1.一定要在將操作添加到操作隊列中之前添加操作依賴    [block2 addDependency:block1];    [block3 addDependency:block2];    [inO addDependency:block3];    // 2.不要添加循環相依性    [block1 addDependency:block3];        [[[NSOperationQueue alloc] init] addOperation:block1];    [[[NSOperationQueue alloc] init] addOperation:block2];    [[[NSOperationQueue alloc] init] addOperation:block3];        [[NSOperationQueue mainQueue] addOperation:inO];}- (void)test {    NSLog(@"測試%s-----%@", __func__, [NSThread currentThread]);}#pragma mark#pragma mark - NSOperation進階操作2- (void)highLevelTest2 {    /**     NSOperation進階操作     應用情境:提高使用者體驗第一,當使用者操作時,取消一切跟使用者當前操作無關的進程,提升流暢度     1.添加操作依賴     2.管理操作:重點!是操作隊列的方法     2.1暫停/恢複 取消 操作     2.2開啟合適的線程數量!(最多不超過6條)          一般開發的時候,會將操作隊列設定成一個全域的變數(屬性)     */        NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"---------");    }];        NSOperationQueue *queue = [[NSOperationQueue alloc] init];        [queue addOperationWithBlock:^{        [self test];    }];        [queue addOperation:block1];        // 1.暫停操作  開始滾動的時候    [queue setSuspended:YES];        // 2.恢複操作  滑動結束的時候    [queue setSuspended:NO];        // 3.取消所有操作  接收到記憶體警告    [queue cancelAllOperations];        // 3.1補充:取消單個操作調用該NSOperation的cancel方法    [block1 cancel];        // 4.設定線程最大並發數,開啟合適的線程數量 執行個體化操作隊列的時候    [queue setMaxConcurrentOperationCount:6];        /**     遇到並發編程,什麼時候選擇 GCD, 什麼時候選擇NSOperation     1.簡單的開啟線程/回到主線程,選擇GCD:效率更高,簡單     2.需要管理操作(考慮到使用者互動!)使用NSOperation     */}#pragma mark#pragma mark - NSOperation簡單操作- (void)BaseTest {    // 1.執行個體化操作對象    NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOperation1---------%@", [NSThread currentThread]);    }];        // 往當前操作中追加操作    [blockOperation1 addExecutionBlock:^{        NSLog(@"addblockOperation1.1-----%@", [NSThread currentThread]);    }];        [blockOperation1 addExecutionBlock:^{        NSLog(@"addblockOperation1.2-----%@", [NSThread currentThread]);    }];        /**     當 NSBlockOperation中的任務數 > 1 之後,無論是將操作添加到主線程還是在主線程直接執行 start, NSBlockOperation中的任務執行順序都不確定,執行線程也不確定!     一般在開發的時候,要避免向 NSBlockOperation 中追加任務!     如果任務都是在子線程中執行,並且不需要保證執行順序!可以直接追加任務     */        NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOperation2---------%@", [NSThread currentThread]);    }];        NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOperation3---------%@", [NSThread currentThread]);    }];        // 將操作添加到非主隊列中    //    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    //    //    [queue addOperation:blockOperation1];    //    [queue addOperation:blockOperation2];    //    [queue addOperation:blockOperation3];        // 將操作添加到主隊列中    [[NSOperationQueue mainQueue] addOperation:blockOperation1];    [[NSOperationQueue mainQueue] addOperation:blockOperation2];    [[NSOperationQueue mainQueue] addOperation:blockOperation3];}

 

 

3、NSOperation實現線程間通訊

1)利用代理進行訊息傳遞

@interface ViewController ()<MyOperationDelegate>@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation ViewController- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {        NSLog(@"%s-----%@", __func__, [NSThread currentThread]);        NSString *urlString = @"http://h.hiphotos.baidu.com/image/pic/item/30adcbef76094b366b2389d7a4cc7cd98d109d53.jpg";        // 1.建立操作對象    MyOperation *myO = [[MyOperation alloc] init];        myO.delegate = self;        // 3.告訴 myO 下載哪一張圖片    myO.urlString = urlString;        NSOperationQueue *queue = [[NSOperationQueue alloc] init];    [queue setMaxConcurrentOperationCount:6];        // 4.將操作添加到操作隊列中    [queue addOperation:myO];        NSLog(@"end");}#pragma mark#pragma mark - 實現操作的代理方法- (void)downImage:(UIImage *)image {    NSLog(@"%s------%@", __func__, [NSThread currentThread]);    self.imageView.image = image;}@protocol MyOperationDelegate <NSObject>- (void)downImage:(UIImage *)image;@end@interface MyOperation : NSOperation@property (nonatomic, copy) NSString *urlString;@property (nonatomic, weak) id<MyOperationDelegate> delegate;@end@implementation MyOperation#pragma mark#pragma mark - 重寫NSOperation的main方法// 當把自訂的操作添加到操作隊列中,或者直接叫用作業的 start 方法後,都會自動來執行main 方法中的內容- (void)main {    NSLog(@"%s------%@", __func__, [NSThread currentThread]);        UIImage *image = [self downLoadImageSubThread];        // 回到主線程執行代理方法    dispatch_async(dispatch_get_main_queue(), ^{        if ([self.delegate respondsToSelector:@selector(downImage:)]) {            [self.delegate downImage:image];        }    });    }#pragma mark#pragma mark - 下載網狀圖片的方法- (UIImage *)downLoadImageSubThread {        NSURL *url = [NSURL URLWithString:self.urlString];        NSData *data = [NSData dataWithContentsOfURL:url];        NSLog(@"下載完成");    return [UIImage imageWithData:data];    }@end

 

 

2)利用通知實現訊息傳遞

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIImageView *imageView04;@end@implementation ViewController- (void)viewDidLoad {    NSLog(@"%s-----%@", __func__, [NSThread currentThread]);    // 註冊通知觀察者    // object:nil ,nil可以保證觀察者接收任意類型的通知!    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setUpImageWithNotify:) name:@"FinishDownLoadImage" object:nil];}- (void)dealloc {    // 通知用完之後需要移除    [[NSNotificationCenter defaultCenter] removeObserver:self];}// 接收到通知之後,執行的方法 noti:接收到的通知- (void)setUpImageWithNotify:(NSNotification *)noti {    NSLog(@"%s-----%@", __func__, [NSThread currentThread]);    // 顯示圖片    self.imageView04.image = noti.object;}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {        NSLog(@"%s-----%@", __func__, [NSThread currentThread]);        // 1.建立操作隊列    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    [queue setMaxConcurrentOperationCount:6];        // 2.告訴操作下載哪張圖片    MyOperation *myO = [[MyOperation alloc] init];        myO.urlString = @"http://h.hiphotos.baidu.com/image/pic/item/72f082025aafa40f7c884d31af64034f79f0198b.jpg";        // 3.將操作添加到操作隊列,會自動叫用作業中的main 方法    [queue addOperation:myO];        NSLog(@"end");}/**************************************************/// 自訂NSOperation類@interface MyOperation : NSOperation@property (nonatomic, copy) NSString *urlString;@end// 實現自訂NSOperation類@implementation MyOperation- (void)main {    NSLog(@"%s-----%@", __func__, [NSThread currentThread]);        // 在子線程下載好圖片後再傳給主線程    UIImage *image = [self downLoadImage:self.urlString];        // 圖片下載完畢之後,利用通知告訴控制器,圖片下載結束,並且將下載好的圖片傳遞給控制器    // 在主線程發送通知    dispatch_async(dispatch_get_main_queue(), ^{        [[NSNotificationCenter defaultCenter] postNotificationName:@"FinishDownLoadImage" object:image];    });    }- (UIImage *)downLoadImage:(NSString *)urlString {        NSURL *url = [NSURL URLWithString:urlString];        NSData *data = [NSData dataWithContentsOfURL:url];        return [UIImage imageWithData:data];    }

 

3)利用block進行訊息傳遞

@interface ViewController ()@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation ViewController- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {        NSLog(@"%s----%@",__func__, [NSThread currentThread]);        NSString *urlString = @"http://h.hiphotos.baidu.com/image/pic/item/72f082025aafa40f7c884d31af64034f79f0198b.jpg";        // 2.建立操作    MyOperation *mo = [[MyOperation alloc] init];    mo.urlString = urlString;        mo.view = self.view;        [mo downLoadWebImageWithBlock:^(UIImage *image) {        self.imageView.image = image;    }];        [mo setCompletionBlock:^{        NSLog(@"圖片下載完成");    }];        NSLog(@"end");    }/*********************************************************/// 自訂NSOperation類typedef void(^downLoadBlock)(UIImage *image);@interface MyOperation : NSOperation@property (nonatomic, strong) UIView *view;@property (nonatomic, copy) NSString *urlString;@property (nonatomic, copy) downLoadBlock block;- (void)downLoadWebImageWithBlock:(downLoadBlock)blk;@end// 實現自訂NSOperation類@implementation MyOperation#pragma mark#pragma mark - 實現block方法,方便直接斷行符號調用- (void)downLoadWebImageWithBlock:(downLoadBlock)blk {    if (blk) {        self.block = blk;                dispatch_async(dispatch_get_global_queue(0, 0), ^{            UIImage *image = [self downLoadImage:self.urlString];                        dispatch_async(dispatch_get_main_queue(), ^{                                if (self.block) {                    self.block(image);                }                            });        });    }}#pragma mark#pragma mark - 下載圖片的方法- (UIImage *)downLoadImage:(NSString *)strUrl {        NSLog(@"%s----%@",__func__, [NSThread currentThread]);        NSURL *url = [NSURL URLWithString:strUrl];        NSData *data = [NSData dataWithContentsOfURL:url];        NSLog(@"下載完成");        return [UIImage imageWithData:data];    }@end

 

 

四、與GCD比較

GCD:

將任務(block)添加到隊列(串列/並發/主隊列),並且指定任務執行的函數(同步/非同步)
GCD是底層的C語言構成的API
iOS 4.0 推出的,針對多核處理器的並發技術
在隊列中執行的是由 block 構成的任務,這是一個輕量級的資料結構
要停止已經加入 queue 的 block 需要寫複雜的代碼
需要通過 Barrier 或者同步任務設定任務之間的依賴關係
只能設定隊列的優先順序
進階功能:
一次性 once
延遲操作 after
調度組

NSOperation:

核心概念:把操作(非同步)添加到隊列(全域的並發隊列)
OC 架構,更加物件導向,是對 GCD 的封裝
iOS 2.0 推出的,蘋果推出 GCD 之後,對 NSOperation 的底層全部重寫
Operation作為一個對象,為我們提供了更多的選擇
可以隨時取消已經設定要準備執行的任務,已經執行的除外
可以跨隊列設定作業的依賴關係
可以設定隊列中每一個操作的優先順序
進階功能:
最大操作並發數(GCD不好做)
繼續/暫停/全部取消
跨隊列設定作業的依賴關係

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.