iOS多線程開發之NSOperation用法總結

NSOperation的作用

配合使用NSOperation和NSOperationQueue也能實現多線程編程

NSOperation和NSOperationQueue實現多線程的具體步驟

  • 先將需要執行的操作封裝到一個NSOperation對象中
  • 然后將NSOperation對象添加到NSOperationQueue中
  • 系統會自動將NSOperationQueue中的NSOperation取出來
  • 將取出的NSOperation封裝的操作放到一條新線程中執行

注意:

  • NSOperation是個抽象類,并不具備封裝操作的能力,必須使用它的子類
  • 使用NSOperation子類的方式有3種:
  • NSInvocationOperation
  • NSBlockOperation
  • 自定義子類繼承NSOperation,實現內部相應的方法

NSInvocationOperation類

  • 創建NSInvocationOperation對象
-(id)initWithTarget:(id)targetselector:(SEL)selobject:(id)arg;
  • 調用start方法開始執行操作
-(void)start;

一旦執行操作,就會調用target的sel方法

  • 代碼:
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    [op start];
 - (void)run
{
    NSLog(@"------%@", [NSThread currentThread]);
}
  • 注意:
  • 默認情況下,調用了start方法后并不會開一條新線程去執行操作,而是在當前線程同步執行操作
  • 只有將NSOperation放到一個NSOperationQueue中,才會異步執行操作
  • 此類僅當了解,在開發中并不常用

NSBlockOperation類

  • 創建NSBlockOperation對象
+(id)blockOperationWithBlock:(void(^)(void))block;
  • 通過addExecutionBlock:方法添加更多的操作
-(void)addExecutionBlock:(void(^)(void))block;
  • 代碼:
 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        // 在主線程
        NSLog(@"下載1------%@", [NSThread currentThread]);
    }];
    
    // 添加額外的任務(在子線程執行)
    [op addExecutionBlock:^{
        NSLog(@"下載2------%@", [NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
        NSLog(@"下載3------%@", [NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
        NSLog(@"下載4------%@", [NSThread currentThread]);
    }];
    
    [op start];
  • 注意:只要NSBlockOperation封裝的操作數 >1,就會異步執行操作

NSOperationQueue

  • NSOperationQueue的作用

  • NSOperation可以調用start方法來執行任務,但默認是同步執行的

  • 如果將NSOperation添加到NSOperationQueue(操作隊列)中,系統會自動異步執行NSOperation中的操作

  • 添加操作到NSOperationQueue中

-(void)addOperation:(NSOperation*)op;
-(void)addOperationWithBlock:(void(^)(void))block;
  • 代碼:
  • 方法一:
    // 創建隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 創建操作
        NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"download1 --- %@", [NSThread currentThread]);
        }];
    
    //添加操作到隊列中
        [queue addOperation:op1];
  • 方法二:
 // 創建隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//添加操作到隊列中
 [queue addOperationWithBlock:^{
        NSLog(@"download1 --- %@", [NSThread currentThread]);
    }];

NSOperationQueue的隊列類型與GCD的隊列類型對比

  • GCD的隊列
  • 并發隊列
    • 自己創建的
    • 全局
  • 串行隊列
    • 主隊列
    • 自己創建的
  • NSOperationQueue的隊列
  • 主隊列
    [NSOperationQueue mainQueue]
 - 凡是添加到主隊列中的任務(NSOperation),都會放到主線程中執行
  • 非主隊列(其他隊列)
     [[NSOperationQueue alloc] init]
 - 同時包含了:串行、并發功能
 - 添加到這種隊列中的任務(NSOperation),就會自動放到子線程中執行

最大并發數

  • 什么是并發數

  • 同時執行的任務數

  • 比如,同時開3個線程執行3個任務,并發數就是3

  • 最大并發數的相關方法

-(NSInteger)maxConcurrentOperationCount;
-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;
  • 代碼
     // 創建隊列
     NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
     // 設置最大并發操作數
     // queue.maxConcurrentOperationCount = 2;// 并發隊列
     queue.maxConcurrentOperationCount = 1; // 就變成了串行隊列
     // 添加操作
     [queue addOperationWithBlock:^{
          NSLog(@"download1 --- %@", [NSThread currentThread])
      }];
     [queue addOperationWithBlock:^{
          NSLog(@"download2 --- %@", [NSThread currentThread])
      }];
     [queue addOperationWithBlock:^{
          NSLog(@"download3 --- %@", [NSThread currentThread])
      }];
    
    

隊列的取消、暫停、恢復

  • 取消隊列的所有操作
-(void)cancelAllOperations;

提示:也可以調用NSOperation的-(void)cancel方法取消單個操作

  • 暫停和恢復隊列
  -(void)setSuspended:(BOOL)b;// YES代表暫停隊列,NO代表恢復隊列
  - (BOOL)isSuspended
  • 代碼
 // 恢復隊列,繼續執行
 // self.queue.suspended = NO;

 // 暫停(掛起)隊列,暫停執行
 // self.queue.suspended = YES;

 // 取消隊列的所有操作
 [self.queue cancelAllOperations];

操作依賴

  • NSOperation之間可以設置依賴來保證執行順序
  • 比如一定要讓操作A執行完后,才能執行操作B,可以這么寫
[operationB addDependency:operationA];// 操作B依賴于操作A
  • 也可以在不同queue的NSOperation之間創建依賴關系
  • 代碼
    // 創建隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 添加操作
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download1----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download2----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download3----%@", [NSThread  currentThread]);
    }];
   // 設置依賴(保證op3在op1和op2都執行完之后再執行)
    [op3 addDependency:op1];
    [op3 addDependency:op2];
  • 注意:不能相互依賴
  • 比如A依賴B,B依賴A

線程之間的通信

  • 舉例:在子線程下載圖片,再回答到主線程在imageView添加圖片
  • 看代碼:
   [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        // 圖片的網絡路徑
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
        
        // 加載圖片
        NSData *data = [NSData dataWithContentsOfURL:url];
        
        // 生成圖片
        UIImage *image = [UIImage imageWithData:data];
        
        // 回到主線程
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
        }];
    }];

操作的監聽

  • 可以監聽一個操作的執行完畢
-(void(^)(void))completionBlock;
-(void)setCompletionBlock:(void(^)(void))block;

自定義NSOperation

  • 自定義NSOperation的步驟很簡單
  • 重寫-(void)main方法,在里面實現想執行的任務
  • 重寫-(void)main方法的注意點
  • 自己創建自動釋放池(因為如果是異步操作,無法訪問主線程的自動釋放池)
  • 經常通過-(BOOL)isCancelled方法檢測操作是否被取消,對取消做出響應
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容

  • NSThread 第一種:通過NSThread的對象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 830評論 0 3
  • 在這篇文章中,我將為你整理一下 iOS 開發中幾種多線程方案,以及其使用方法和注意事項。當然也會給出幾種多線程的案...
    張戰威ican閱讀 611評論 0 0
  • 多線程基本概念 單核CPU,同一時間cpu只能處理1個線程,只有1個線程在執行 。多線程同時執行:是CPU快速的在...
    WeiHing閱讀 718評論 1 5
  • 世界上最可怕的事是當我長大之后你已經老去~ 1 曾經報名參加了學校一個訪問孤寡老人的志愿活動,地點是廈門...
    小小薰閱讀 647評論 0 0
  • 當我一個人躺在床上的時候,很大一部分感覺,不是空虛,也不是寂寞。而是一種叫做迷茫的感覺。 就像一個浪人漂泊在海上。...
    陳丶胡子閱讀 290評論 0 0