IOS中級篇—— 多線程--NSOperation,ios--nsoperation
NSOperation 操作 任務是對代碼的封裝, 操作是對任務的封裝 --目的:就是可以隨時的暫停/恢複/取消任務;
NSOperation 對GCD的封裝. OC 運用起來更加方便. 抽象類別. 車
NSOperation的使用:
<1> 操作直接調用 start方法,就是在當前線程執行(Block中封裝的任務數大於1的情況除外).
<2> 就是將操作放在隊列中.自動的幫我們開啟線程,來執行操作.
兩個子類:
NSInvocationOperation: 調用 1. NSOperation的兩個子類的使用: // 建立一個NSOpertation的子類 NSInvocationOperation NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(longTimeOperation) object:nil]; [op1 start]; //調用 開始任務 不會開啟線程。 在主線程中執行 NSBlockOperation:Block // 建立一個NSOpertation的子類 NSBlockOperation NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
// Block中封裝操作.
[self longTimeOperation]; }];// 追加一個操作(任務). [op2 addExecutionBlock:^{ NSLog(@"下載圖片1:%@",[NSThread currentThread]); }]; // 追加一個操作(任務). [op2 addExecutionBlock:^{ NSLog(@"下載圖片2:%@",[NSThread currentThread]); }];// [op2 start]; // NSBlockOperation 直接調用start方法: // 如果只有一個任務:在主線程中執行 // 如果有多個任務:會開啟多條線程,在主線程中和子線程中都執行任務. // 多個任務都是同時執行的.
// 操作完成之後的回調(非同步回調)
// 一般用的不多.
op2.completionBlock = ^{
// 操作執行完畢的回調(什麼時候操作執行完畢,我們並不知道)
NSLog(@"操作1執行完畢%@",[NSThreadcurrentThread]); }; // 建立一個非隊列: 非主隊列:非主隊列存放的操作都在子主線程中執行. NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 擷取一個主隊列 主隊列:主隊列存放的操作在主線程中執行 NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; // 使用:將操作添加到隊列中 [queue addOperation:op2]; [queue addOperation:op1]; // 將操作添加到隊列中,會自動(開啟線程)的非同步執行操作. 任務增加到隊列中。 就調用Operation裡的main方法。 然後自動執行任務
任務依賴 [op1 addDependency:op2]; //等任務 op2 執行完後 在執行op1 [op2 addDependency:op3]; //等任務 op3 執行完後 在執行op2 這兩句的效果是: op3最先執行 在op2 執行 最後執行 op1進階操作:一般情況下 隊列都用懶載入的方法來實現@property (nonatomic, strong) NSOperationQueue *queue; // 懶載入Queue
-(NSOperationQueue *)queue
{
if (!_queue) {
_queue = [[NSOperationQueuealloc] init];
// 最大並發數為6 .
[_queuesetMaxConcurrentOperationCount:6];
}
return_queue; }在block中 用到self 都要用weak方式 否則會造循環參考問題_weaktypeof(self) wself = self; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ [wself longTimeOperation];}]; // 取消單個操作,一般也不用. [op2 cancel]; // 暫停隊列中的操作 [self.queue setSuspended:YES]; // 恢複隊列中的操作 [self.queue setSuspended:NO]; // 取消所有操作,對於已經取消的操作,就永遠取消了,不會再次開啟 [self.queue cancelAllOperations];
// 自訂NSOperation; 線程間通訊 NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{
// 執行的任務
UIImage *image = [selflongTimeOperation];
NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{ self.imageView.image = image; }]; [[NSOperationQueue mainQueue] addOperation:op]; }];下面都是自訂NSOperation方式// 不同對象間的通訊三種方式 1.通知1.>// 下載圖片完成的時候 發送一個通知,將圖片傳遞出去(通知中的參數是image) [[NSNotificationCenter defaultCenter] postNotificationName:@"ITDownloadImageOperation" object:image];
2.>// 在需要用到內容的類 註冊通知的接收者.[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setUpImage:) name:@"ITDownloadImageOperation" object:nil];3.>// 通知傳遞的參數,永遠是一個NSNotification; 註冊通知時用到的方法 - (void)setUpImage:(NSNotification *)notify { // 回到主線程 dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"setUpImage%@",[NSThread currentThread]); // notify.object就是通知傳遞的對象. // 本次通知中,通知傳遞的對象就是這個操作 ITDownloadImageOperation *op = notify.object; self.imageView.image = op.image; }); } 2.代理 參考以前代理的寫法 一模一樣
3.block// 1.定義一個block類型 參數為imagetypedefvoid (^downloadImageOperationBlock)(UIImage *image);// 2.定義一個Block的屬性@property (nonatomic, copy) downloadImageOperationBlock downBlock;// 3. 設定Block中想要執行的內容;// Block 只是一個塊代碼.Block中的內容什麼時候執行,和定義其中的內容是分開進行的.op.downBlock = ^(UIImage *image){ // Block中想要執行的內容. self.imageView.image = image;};// 4. 在 main執行這個Block -(void)main { @autoreleasepool {// 在子線程下載圖片 UIImage *image = [self downloadImage]; // 回到主線程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ if (self.downBlock) { self.downBlock(image); NSLog(@"執行Block中的內容: 設定圖片");}}];}}3.block 方法形式 傳單個對象 如UIImage前兩步 跟上面一樣// 3.定義一個方法,負責傳遞Block // (downloadImageOperationBlock)blk:把Block當做一個參數來傳遞 - (void)setUpImageWithBlock:(downloadImageOperationBlock)blk;// 4.實現這個方法,self.downBlock賦值 -(void)setUpImageWithBlock:(downloadImageOperationBlock)blk { if (blk) { // 給self.downBlock賦值(Block內部執行的方法) self.downBlock = blk; } } // 5.Block中的內容是一個參數 [op setUpImageWithBlock:^(UIImage *image) { // 定義一個Block中執行的內容. self.imageView.image = image; }]; // 6.調用block 與上面第4步一樣 3.block 方法形式 傳本身類 些方法跟 傳單個對象用法一模一樣 只是在調用bolck時傳self self.downBlock(image); 在設定值的時候 用對象.某個對象 ITDownloadOperationBlock *op = [[ITDownloadOperationBlockalloc] init]; [op setUpImageWithBlock:^(ITDownloadOperationBlock *op) { self.imageView.image = op.image; }];