配合使用NSOperation和NSOperationQueue也能實現多線程編程
封裝操作的時候可以使用NSOperation的子類實現,因為NSOperation是抽象類,所以不能直接使用。
三種方式:
下面分別講解三種方式:
1、NSInvocationOperation
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;- (void)start;//一旦執行操作,就會調用target的sel方法注意:
默認情況下,調用了start方法后并不會開一條新線程去執行操作,而是在當前線程同步執行操作
只有將NSOperation放到一個NSOperationQueue中,才會異步執行操作

2、創建NSBlockOperation對象
+ (id)blockOperationWithBlock:(void (^)(void))block;通過addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;注意:只要NSBlockOperation封裝的操作數 > 1,就會異步執行操作

3、自定義NSOperation
自定義NSOperation的步驟很簡單
重寫- (void)main方法,在里面實現想執行的任務
重寫- (void)main方法的注意點:
自己創建自動釋放池(因為如果是異步操作,無法訪問主線程的自動釋放池)
經常通過- (BOOL)isCancelled方法檢測操作是否被取消,對取消做出響應
由于取消同樣會繼續執行當前正在執行的任務, 所以耗時操作需要手動判斷是否已經取消
if (self.isCancelled) return;// 一般情況下, 在做企業開發時候,都會定義一個全局的自定義隊列, 便于使用
NSOperationQueue *queue = [[NSOperationQueue alloc] init];NSOperationQueue的作用
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;- (void)addOperationWithBlock:(void (^)(void))block;設置最大并發數
- (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;- (void)cancelAllOperations;// 取消隊列中所有的任務的執行// 取消和暫停一樣, 是取消后面的任務, 不能取消當前正在執行的任務// 注意: 取消是不可以恢復的提示:也可以調用NSOperation的- (void)cancel方法取消單個操作
暫停和恢復隊列
- (void)setSuspended:(BOOL)b;// YES代表暫停隊列,NO代表恢復隊列- (BOOL)isSuspended;// 只要設置隊列的suspended為YES, 那么就會暫停隊列中其它任務的執行// 也就是說不會再繼續執行沒有執行到得任務// 只要設置隊列的suspended為NO, 那么就會恢復隊列中其它任務的執行// 注意: 設置為暫停之后, 不會立即暫停// 會繼續執行當前正在執行的任務, 直到當前任務執行完畢, 就不會執行下一個任務了// 也就是說, 暫停其實是暫停下一個任務, 而不能暫停當前任務// 注意: 暫停是可以恢復的NSOperation之間可以設置依賴來保證執行順序
比如一定要讓操作A執行完后,才能執行操作B,可以這么寫
[operationB addDependency:operationA]; // 操作B依賴于操作A可以在不同queue的NSOperation之間創建依賴關系
可以監聽一個操作的執行完畢
- (void (^)(void))completionBlock;- (void)setCompletionBlock:(void (^)(void))block;// 4.監聽op4什么時候執行完畢op4.completionBlock = ^{ NSLog(@"op4中所有的操作都執行完畢了");};實例一:
NSBlockOperation簡單使用,并添加任務
//1. 封裝任務 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ // 主線程 NSLog(@"1---%@", [NSThread currentThread]); }]; // 2.追加其它任務 // 注意: 在沒有隊列的情況下, 如果給BlockOperation追加其它任務, 那么其它任務會在子線程中執行 [op1 addExecutionBlock:^{ NSLog(@"2---%@", [NSThread currentThread]); }]; [op1 addExecutionBlock:^{ NSLog(@"3---%@", [NSThread currentThread]); }]; // 3.啟動任務 [op1 start];實例二:
NSInvocationOperation的簡單使用
// 1.封裝任務NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];// 2.要想執行任務必須調用start[op1 start];實例三:
創建各種操作并添加到隊列里面.
// 1.創建隊列 /* GCD中有哪些隊列: 并發: 自己創建, 全局 串行: 自己創建, 主隊列 NSOperationQueue: 主隊列: mainQueue 自己創建: 會在子線程中執行 */ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.創建任務 // 只要是自己創建的隊列, 就會在子線程中執行 // 而且默認就是并發執行 //第一種 NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil]; //第二種 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"2 == %@", [NSThread currentThread]); }]; // 注意: 如果是使用block來封裝任務, 那么有一種更簡便的方法 // 只要利用隊列調用addOperationWithBlock:方法, 系統內部會自動封裝成一個NSBlockOperation然后再添加到隊列中 //第三種 [queue addOperationWithBlock:^{ NSLog(@"3 == %@", [NSThread currentThread]); }]; // 3.添加任務到隊列中 // 只要將任務添加到隊列中, 隊列會自動調用start [queue addOperation:op1]; [queue addOperation:op2];實例四:
最大執行數量
NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 自己創建的隊列默認是并發,如果設置maxConcurrentOperationCount = 1,就是串行// 注意: 不能設置為0, 如果設置為0就不行執行任務/// 默認情況下maxConcurrentOperationCount = -1,是并行// 在開發中并發數最多盡量不要超過5~6條queue.maxConcurrentOperationCount = 0;實例四:
線程間通訊
// 1.創建一個隊列 // 一般情況下, 在做企業開發時候, 都會定義一個全局的自定義隊列, 便于使用 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.添加一個操作下載第一張圖片 __block UIImage *image1 = nil; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSURL *url = [NSURL URLWithString:@"http://imgcache.mysodao.com/img2/M04/8C/74/CgAPDk9dyjvS1AanAAJPPRypnFA573_700x0x1.JPG"]; NSData *data = [NSData dataWithContentsOfURL:url]; image1 = [UIImage imageWithData:data]; }]; // 3.添加一個操作下載第二張圖片 __block UIImage *image2 = nil; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSURL *url = [NSURL URLWithString:@"http://imgcache.mysodao.com/img1/M02/EE/B5/CgAPDE-kEtqjE8CWAAg9m-Zz4qo025-22365300.JPG"]; NSData *data = [NSData dataWithContentsOfURL:url]; image2 = [UIImage imageWithData:data]; }]; // 4.添加一個操作合成圖片 NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ UIGraphicsBeginImageContext(CGSizeMake(200, 200)); [image1 drawInRect:CGRectMake(0, 0, 100, 200)]; [image2 drawInRect:CGRectMake(100, 0, 100, 200)]; UIImage *res = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // 5.回到主線程更新UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.imageView.image = res; }]; }]; // 6.添加依賴 [op3 addDependency:op1]; [op3 addDependency:op2]; // 7.添加操作到隊列中 [queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3];新聞熱點
疑難解答