線程間通訊
一、NSThread
1.簡單說明
①線程間通信:在1個進程中,線程往往不是孤立存在的,多個線程之間需要經常進行通信
②線程間通信的體現
- 1個線程傳遞數據給另1個線程
- 在1個線程中執行完特定任務后,轉到另1個線程繼續執行任務
③線程間通信常用方法
// waitUntilDone的含義: // 如果傳入的是YES: 那么會等到主線程中的方法執行完畢, 才會繼續執行下面其他行的代碼 // 如果傳入的是NO: 那么不用等到主線程中的方法執行完畢, 就可以繼續執行下面其他行的低嗎 /* * 回到主線程執行,執行self的showImage方法,參數是image */ [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES]; /* * 回到xx線程執行aSelector方法,參數是arg */ - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
④案例,下載圖片,然后在屏幕上顯示
注意:
雖然有時候可以在子線程中操作UI,但是開發中千萬不要這樣干因為如果是在子線程中操作UI, 有時候行, 有時候不行
- (void)viewDidLoad { // 1.給定圖片的url NSURL *url = [NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/e4dde71190ef76c666af095f9e16fdfaaf516741.jpg"]; // 2.開啟線程,在后台執行download方法 [self performSelectorInBackground:@selector(download:) withObject:url]; } - (void)download:(NSURL *)url { // 在子線程下載圖片 NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; // 設置圖片,執行self.imageView的setImage:方法 // [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; // 另一張設置圖片的方法 // 回到主線程中執行 showImage:方法,在此方法中設置圖片 [self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES]; } -(void)showImage:(UIImage *)image { // 更新UI self.imageView.image = image; }
幾個常用打印時間的方法
//獲得當前時間,double型 CFAbsoluteTime begin = CFAbsoluteTimeGetCurrent(); // 獲得當前時間 NSDate *begin = [NSDate date]; // 執行一些操作之后的時間 NSDate *end = [NSDate date]; // 時差 NSLog(@"花費了多少秒 %f", [end timeIntervalSinceDate:begin]);
二、GCD
- 案例,下載圖片,然后在屏幕上顯示
在dispatch_get_main_queue() 隊列中
如果是通過異步函數調用, 那么會先執行完所有的代碼, 再更新UI
如果是同步函數調用, 那么會先更新UI, 再執行其它代碼
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 1.下載圖片(耗時) dispatch_async(queue, ^{ NSLog(@"%@", [NSThread currentThread]); // 1.創建URL NSURL *url = [NSURL URLWithString:@"http://stimgcn1.s-msn.com/msnportal/ent/2015/08/04/7a59dbe7-3c18-4fae-bb56-305dab5e6951.jpg"]; // 2.通過NSData下載圖片 NSData *data = [NSData dataWithContentsOfURL:url]; // 3.將NSData轉換為圖片 UIImage *image = [UIImage imageWithData:data]; // 4.更新UI // self.imageView.image = image; // NSLog(@"更新UI完畢"); // 如果是通過異步函數調用, 那么會先執行完所有的代碼, 再更新UI // 如果是同步函數調用, 那么會先更新UI, 再執行其它代碼 dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"%@", [NSThread currentThread]); self.imageView.image = image; NSLog(@"更新UI完畢"); }); NSLog(@"Other"); });
三、NSOperation
1.第一種方法
// 1.創建一個新的隊列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.添加任務(操作) [queue addOperationWithBlock:^{ // 2.1在子線程中下載圖片 NSURL *url = [NSURL URLWithString:@"http://imgcache.mysodao.com/img2/M04/8C/74/CgAPDk9dyjvS1AanAAJPpRypnFA573_700x0x1.JPG"]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; // 2.2回到主線程更新UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.imageView.image = image; }]; }];
2.第二種方法(添加依賴)
/ 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];