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類型 ?參數為image
typedefvoid (^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;
? }];? ? ?
? ?
?