多線程編程2-NSOperation

回到頂部

前言

1.上一講簡單介紹了NSThread的使用,雖然也可以實現多線程編程,但是需要我們去管理線程的生命周期,還要考慮線程同步、加鎖問題,造成一些性能上的開銷。我們也可以配合使用NSOperation和NSOperationQueue實現多線程編程,實現步驟大致是這樣的:

1> 先將需要執行的操作封裝到一個NSOperation對象中

2> 然后將NSOperation對象添加到NSOperationQueue中

3> 系統會自動將NSOperation中封裝的操作放到一條新線程中執行

在此過程中,我們根本不用考慮線程的生命周期、同步、加鎖等問題

下面列舉一個應用場景,比如微博的粉絲列表:

每一行的頭像肯定要從新浪服務器下載圖片后才能顯示的,而且是需要異步下載。這時候你就可以把每一行的圖片下載操作封裝到一個NSOperation對象中,上面有6行,所以要創建6個NSOperation對象,然后添加到NSOperationQueue中,分別下載不同的圖片,下載完畢后,回到對應的行將圖片顯示出來。

?

2.默認情況下,NSOperation并不具備封裝操作的能力,必須使用它的子類,使用NSOperation子類的方式有3種:

1>?NSInvocationOperation

2> NSBlockOperation

3> 自定義子類繼承NSOperation,實現內部相應的方法

這講先介紹如何用NSOperation封裝一個操作,后面再結合NSOperationQueue來使用。

?

回到頂部

一、NSInvocationOperation

1 NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"mj"] autorelease];
2 [operation start];

* 第1行初始化了一個NSInvocationOperation對象,它是基于一個對象和selector來創建操作

* 第2行調用了start方法,緊接著會馬上執行封裝好的操作,也就是會調用self的run:方法,并且將@"mj"作為方法參數

* 這里要注意:默認情況下,調用了start方法后并不會開一條新線程去執行操作,而是在當前線程同步執行操作。只有將operation放到一個NSOperationQueue中,才會異步執行操作。

?

回到頂部

二、NSBlockOperation

1.同步執行一個操作

1 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){
2         NSLog(@"執行了一個新的操作");
3 }];
4  // 開始執行任務
5 [operation start];

* 第1行初始化了一個NSBlockOperation對象,它是用一個Block來封裝需要執行的操作

*?第2行調用了start方法,緊接著會馬上執行Block中的內容

* 這里還是在當前線程同步執行操作,并沒有異步執行

?

2.并發執行多個操作

復制代碼
 1 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){2   NSLog(@"執行第1次操作,線程:%@", [NSThread currentThread]);3 }];4 5 [operation addExecutionBlock:^() {6   NSLog(@"又執行了1個新的操作,線程:%@", [NSThread currentThread]);7 }];8 9 [operation addExecutionBlock:^() {
10   NSLog(@"又執行了1個新的操作,線程:%@", [NSThread currentThread]);
11 }];
12 
13 [operation addExecutionBlock:^() {
14   NSLog(@"又執行了1個新的操作,線程:%@", [NSThread currentThread]);
15 }];
16 
17 // 開始執行任務
18 [operation start];
復制代碼

* 第1行初始化了一個NSBlockOperation對象

* 分別在第5、9、13行通過addExecutionBlock:方法添加了新的操作,包括第1行的操作,一共封裝了4個操作

* 在第18行調用start方法后,就會并發地執行這4個操作,也就是會在不同線程中執行

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

可以看出,每個操作所在線程的num值都不一樣,說明是不同線程

?

回到頂部

三、NSOperation的其他用法

1.取消操作

operation開始執行之后, 默認會一直執行操作直到完成,我們也可以調用cancel方法中途取消操作

[operation cancel];

?

2.在操作完成后做一些事情

如果想在一個NSOperation執行完畢后做一些事情,就調用NSOperation的setCompletionBlock方法來設置想做的事情

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

當operation封裝的操作執行完畢后,就會回調Block里面的內容

?

回到頂部

四、自定義NSOperation

如果NSInvocationOperation和NSBlockOperation不能滿足需求,我們可以直接新建子類繼承NSOperation,并添加任何需要執行的操作。如果只是簡單地自定義NSOperation,只需要重載-(void)main這個方法,在這個方法里面添加需要執行的操作。

下面寫個子類DownloadOperation來下載圖片

1.繼承NSOperation,重寫main方法

DownloadOperation.h

復制代碼
#import <Foundation/Foundation.h>
@protocol DownloadOperationDelegate;@interface DownloadOperation : NSOperation
// 圖片的url路徑
@property (nonatomic, copy) NSString *imageUrl;
// 代理
@property (nonatomic, assign) id<DownloadOperationDelegate> delegate;- (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate;
@end// 圖片下載的協議
@protocol DownloadOperationDelegate <NSObject>
- (void)downloadFinishWithImage:(UIImage *)image;
@end
復制代碼

DownloadOperation.m

復制代碼
 1 #import "DownloadOperation.h"2 3 @implementation DownloadOperation4 @synthesize delegate = _delegate;5 @synthesize imageUrl = _imageUrl;6 7 // 初始化8 - (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate {9     if (self = [super init]) {
10         self.imageUrl = url;
11         self.delegate = delegate;
12     }
13     return self;
14 }
15 // 釋放內存
16 - (void)dealloc {
17     [super dealloc];
18     [_imageUrl release];
19 }
20 
21 // 執行主任務
22 - (void)main {
23     // 新建一個自動釋放池,如果是異步執行操作,那么將無法訪問到主線程的自動釋放池
24     @autoreleasepool {
25         // ....
26     }
27 }
28 @end
復制代碼

* 在第22行重載了main方法,等會就把下載圖片的代碼寫到這個方法中

* 如果這個DownloadOperation是在異步線程中執行操作,也就是說main方法在異步線程調用,那么將無法訪問主線程的自動釋放池,所以在第24行創建了一個屬于當前線程的自動釋放池

?

2.正確響應取消事件

* 默認情況下,一個NSOperation開始執行之后,會一直執行任務到結束,就比如上面的DownloadOperation,默認會執行完main方法中的所有代碼。

* NSOperation提供了一個cancel方法,可以取消當前的操作。

* 如果是自定義NSOperation的話,需要手動處理這個取消事件。比如,一旦調用了cancel方法,應該馬上終止main方法的執行,并及時回收一些資源。

* 處理取消事件的具體做法是:在main方法中定期地調用isCancelled方法檢測操作是否已經被取消,也就是說是否調用了cancel方法,如果返回YES,表示已取消,則立即讓main方法返回。

* 以下地方可能需要調用isCancelled方法:

  • 在執行任何實際的工作之前,也就是在main方法的開頭。因為取消可能發生在任何時候,甚至在operation執行之前。
  • 執行了一段耗時的操作之后也需要檢測操作是否已經被取消
復制代碼
 1 - (void)main {2     // 新建一個自動釋放池,如果是異步執行操作,那么將無法訪問到主線程的自動釋放池3     @autoreleasepool {4         if (self.isCancelled) return;5         6         // 獲取圖片數據7         NSURL *url = [NSURL URLWithString:self.imageUrl];8         NSData *imageData = [NSData dataWithContentsOfURL:url];9         
10         if (self.isCancelled) {
11             url = nil;
12             imageData = nil;
13             return;
14         }
15         
16         // 初始化圖片
17         UIImage *image = [UIImage imageWithData:imageData];
18         
19         if (self.isCancelled) {
20             image = nil;
21             return;
22         }
23         
24         if ([self.delegate respondsToSelector:@selector(downloadFinishWithImage:)]) {
25             // 把圖片數據傳回到主線程
26             [(NSObject *)self.delegate performSelectorOnMainThread:@selector(downloadFinishWithImage:) withObject:image waitUntilDone:NO];
27         }
28     }
29 }
復制代碼

* 在第4行main方法的開頭就先判斷operation有沒有被取消。如果被取消了,那就沒有必要往下執行了

* 經過第8行下載圖片后,在第10行也需要判斷操作有沒有被取消

* 總之,執行了一段比較耗時的操作之后,都需要判斷操作有沒有被取消

* 圖片下載完畢后,在第26行將圖片數據傳遞給了代理(delegate)對象

?

轉載于:https://www.cnblogs.com/pb89/p/4708822.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/258518.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258518.shtml
英文地址,請注明出處:http://en.pswp.cn/news/258518.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python圖片顯示英文字符_python如何解析字符串中出現的英文人名?

這里有四個例子&#xff0c;結果來自google scholarstr1 "Jakes, William C., and Donald C. Cox. Microwave mobile communications. Wiley-IEEE Press, 1994."str2 "Schlegel, David J., Douglas P. Finkbeiner, and Marc Davis. \"Maps of dust infra…

閃回表操作語法+使用閃回刪除

閃回表操作語法 flashback table 【 schema.】 table_name to {【before drop 【rename to new_table_name】 】|【scn | timestamp 】】 expr 【enable | disable 】 triggers}: 參數說明&#xff1a; schema&#xff1a;用戶模式 before drop&#xff1a;表示恢復到刪除…

在現有的python環境下創建另一個python版本【親測有效】

比如&#xff0c;你現在的python環境是3.6&#xff0c;想要使用一個3.5&#xff0c;可以在anaconda環境下使用conda虛擬環境。 第一步&#xff1a; conda create -n py35 【創建Py35虛擬環境】 第二步&#xff1a; 進入環境 activate py35 第三步&#xff1a; 升級或者降…

時間戳

我發現&#xff0c;我在本站公布的文章&#xff0c;url 最后一段都是 134 開頭的一串數字。一開始并沒在意&#xff0c;僅僅想當然以為是程序隨機生成的。 昨天跟程序作者交談的過程中無意問起&#xff0c;他說這是代表時間的。剛才訪問 GoAgent 項目時發現&#xff0c;其作者 …

歐拉函數 - HDU1286

歐拉函數的作用&#xff1a; 有[1,2.....n]這樣一個集合&#xff0c;f(n)這個集合中與n互質的元素的個數。歐拉函數描述了一些列與這個f(n)有關的一些性質&#xff0c;如下&#xff1a; 1、令p為一個素數&#xff0c;n p ^ k&#xff0c;則 f(n) p ^ k - p ^ (k-1) 2、令m&…

其中一個頁簽慢_渭南提升一個大專學歷的有效方法

渭南提升一個大專學歷的有效方法&#xff0c;宏德教育&#xff0c;目前已形成以高等學歷教育為特色王牌&#xff0c;職稱考評、企業內訓為輔助的強力優勢品牌。渭南提升一個大專學歷的有效方法&#xff0c; 獲得發明專利或實用新型專利&#xff0c;且已實施取得效益。出版本專業…

《收集蘋果》 動態規劃入門

問題描寫敘述 平面上有N*M個格子&#xff0c;每一個格子中放著一定數量的蘋果。你從左上角的格子開始&#xff0c;每一步僅僅能向下走或是向右走&#xff0c;每次走到一個格子上就把格子里的蘋果收集起來&#xff0c;這樣下去&#xff0c;你最多能收集到多少個蘋果。 輸入&…

Xamarin XAML語言教程通過ProgressTo方法對進度條設置

2019獨角獸企業重金招聘Python工程師標準>>> Xamarin XAML語言教程通過ProgressTo方法對進度條設置 在ProgressBar中定義了一個ProgressTo方法&#xff0c;此方法也可以用來對進度條當前的進行進行設置&#xff0c;ProgressTo與Progress屬性的不同之處在于ProgressT…

Radar Installation

題目鏈接&#xff1a;http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id27586 題意&#xff1a; 在海岸線上擺放雷達并限定雷達覆蓋半徑d&#xff0c;再以海岸線為軸&#xff0c;給定海上島嶼坐標&#xff0c;求至少需要多少雷達可以覆蓋所以島嶼&#xff0c;如…

win7 + vs2015+ matlab2016a + python3.5安裝matcaffe cpu版本

參考&#xff1a; 1. caffe-windows直接安裝版---編譯后的Release 2.安裝Windows10 和環境下的caffe&#xff08;新版&#xff09; 3.win10vs2015編譯caffe的cpu debug版本、部署matcaffe 主要的方法參考文獻3. 當前caffe-windows僅支持python2.7和3.5 要注意的是&#…

python調用 matlab庫_python調用matlab的搜索結果-阿里云開發者社區

2018python技術問答集錦&#xff0c;希望能給喜歡python的同學一些幫助小編發現問答專區中有很多人在問關于python的問題&#xff0c;小編把這些問題匯總一下&#xff0c;希望能給喜歡python的大家一些啟示和幫助本帖不定期更新&#xff0c;喜歡的可以收藏哦python可能替代Java…

h5新特性

 CSDN博客 Gane_ChengHTML5新特性淺談 發表于2016/10/17 21:25:58 7809人閱讀 分類&#xff1a; 前端 轉載請注明出處&#xff1a; http://blog.csdn.net/gane_cheng/article/details/52819118 http://www.ganecheng.tech/blog/52819118.html &#xff08;瀏覽效果更好…

打勾顯示輸入的密碼 --EditText與setTransformationMethod

實現目標: 實現原理: 為CheckBox添加一個監聽器事件; 實現的源碼: package edu.cquptzx.showPassword; import android.app.Activity; import android.os.Bundle; import android.text.method.HideReturnsTransformationMethod; import android.text.method.PasswordTransforma…

mysql日期截取年月_攝影大賽丨“我遇見最美的光”第五屆全國醫務人員攝影大展 截稿日期2020年8月15日...

截稿日期2020年8月15日《“我遇見最美的光”第五屆全國醫務人員攝影大展》欣賞過山川壯麗&#xff0c;瞻仰過造化旖旎&#xff0c;敬重于生命偉大&#xff0c;感動于英雄凱旋……由《大眾攝影》主辦&#xff0c;正大天晴藥業集團股份有限公司、《中國衛生影像》雜志協辦的“我遇…

iframe子頁面內刷新父頁面中另一個iframe子頁面

框架頁面如下&#xff1a; <div id"aa" style"float: left; height: 500px; border-right-style: solid; border-right-color: #CCCCFF; border-right-width: 2px;"> <IFRAME id"tree" name"tree" src"/ScienProject…

Pytorch的C++接口實踐

Pytorch1.1版本已經提供了相對穩定的c接口&#xff0c;網上也有了眾多的資料供大家參考&#xff0c;進行c的接口的初步嘗試。 可以按照對應的選項下載&#xff0c;下面我們要說的是&#xff1a; 如何利用已經編譯好的官方libtorch庫和其他的opencv庫等聯合編寫應用&#xff1f…

一次慘痛的裝機經歷

最近不小心把我的聯想一體機電腦系統搞壞了&#xff0c;就不得不重裝系統&#xff0c;之前的系統是win7&#xff0c;于是開始的時候想著直接裝win10&#xff0c;升級一下系統。但是裝的過程中總是卡在了win10的正在準備系統中&#xff0c;進度環不轉了。后來轉了多次都不行&…

unity讓對象作為參數_unity-container – 一個unity容器可以將自身的引用作為構造函數參數傳遞嗎?...

簡短的答案是肯定的。當您使用Resolve方法時&#xff0c;這應該自動傳遞。例如&#xff1a;IUnityContainer container new UnityContainer();var something container.Resolve();另外&#xff0c;如果您想查看&#xff0c;這與Prism(CodePlex)使用的技術相同。更新增加測試&…

KnockoutJS + My97DatePicker

如何將Knockoutjs和其他腳本庫結合使用&#xff1f;這里給出一個Knockoutjs與my97datepicker配合使用的例子&#xff0c;例子中使用了ko的自定義綁定功能&#xff1a; ko.bindingHandlers.my97DatePicker {init: function (element, valueAccessor) {$(element).on(click, fun…

HttpClient v4.5 簡單抓取主頁數據

由于工作原因&#xff0c;需要每隔半小時刷新一些網頁&#xff0c;并查看上面的數據是否有更新。這件事能否自動化進行呢&#xff1f;查找了下Java相關的資料&#xff0c;蹦出一個關鍵詞&#xff1a;HttpClient。 HttpClient是常用Http客戶端庫&#xff0c;相關的資料也不少&am…