/**
無論使用哪種多線程技術都可以使用
[NSThread currentThread]跟蹤查看當前執行所在的線程情況。
num = 1表示在主線程上執行的任務
================================================================
1. NSObject多線程技術
1> 使用performSelectorInBackground可以開啓後臺線程,執行selector選擇器選擇的方法
2> 使用performSelectorOnMainThread可以重新回到主線程執行任務,通常用於後臺線程更新界面UI時使用
3> [NSThread sleepForTimeInterval:1.0f];
讓當前線程休眠,通常在程序開發中,用於模擬耗時操作,以便跟蹤不同的併發執行情況!
但是:在程序發佈時,千萬不要保留此方法!不要把測試中的代碼交給客戶,否則會造成不好的用戶體驗。
提示:使用performSelectorInBackground也可以直接修改UI,但是強烈不建議使用。
注意:在使用NSThread或者NSObject的線程方法時,一定要使用自動釋放池,否則容易出現內存泄露。
代碼演示:
(1)NSObject開闢子線程
[self performSelectorInBackground:@selector(bigDemo)withObject:nil];
(2)用NSThread方法開闢子線程
2.1// 類方法新建一個線程,調用@selector方法
[NSThread detachNewThreadSelector:@selector(bigDemo)toTarget:self withObject:nil];
2.2//成員方法
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(bigDemo)object:nil];
// 啓動start線程
[thread start];
被子線程調用的方法:
- (void)bigDemo
{
// 自動釋放池
// 負責其他線程上的內存管理,在使用NSThread或者NSObject的線程方法時,一定要使用自動釋放池
// 否則容易出現內存泄露。
@autoreleasepool {
NSLog(@"%@", [NSThread currentThread]);
// 模擬網絡下載延時,睡眠1秒,通常是在開發中測試使用。
[NSThread sleepForTimeInterval:1.0f];
//強烈不建議直接在後臺線程更新界面UI!
// 模擬獲取到下載的圖像
UIImage *image = [UIImage imageNamed:@"頭像1"];
// 在主線程更新圖像
// 使用self調用updateImage方法在主線程更新圖像
[self performSelectorOnMainThread:@selector(updateImage:)withObject:image waitUntilDone:YES];
// 使用imageView的setImage方法在主線程更新圖像
[_imageView performSelectorOnMainThread:@selector(setImage:)withObject:image waitUntilDone:YES];
}
}
被主線程調用的方法:
- (void)updateImage:(UIImage *)image
{
NSLog(@"更新圖像-> %@", [NSThread currentThread]);
_imageView.image = image;
}
************************************************************
************************************************************
************************************************************
************************************************************
1、GCD演練是基與C語言的NSOPeration&NSOperationQueue基於OC框架寫的
• NSOperation的兩個子類NSInvocationOperation、NSBlockOperation
• 工作原理:用NSOperation封裝要執⾏行的操作
將創建好的NSOperation對象放NSOperationQueue中
啓動OperationQueue開始新的線程執⾏行隊列中的操作
1.1、#pragma mark invocation
- (IBAction)operationDemo1
{
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:selfselector:@selector(opAction)object:nil];
// 如果使用start,會在當前線程啓動操作
// [op1 start];
// 1. 一旦將操作添加到操作隊列,操作就會啓動
[_queue addOperation:op1];
}
#pragma mark - NSOperation演練
- (void)opAction
{
NSLog(@"%@", [NSThread currentThread]);
// 模擬網絡加載延時
[NSThread sleepForTimeInterval:1.0f];
// 模擬獲取到圖像
UIImage *image = [UIImage imageNamed:@"頭像1"];
// 設置圖像,在主線程隊列中設置
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_imageView.image = image;
}];
}
、、、、、、、、、、、、、、、、、、、
1.2#pragma mark blockOperation
- (IBAction)operationDemo2
{
// 用block的最大好處,可以將一組相關的操作,順序寫在一起,便於調試以及代碼編寫
[_queue addOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
// 模擬延時
[NSThread sleepForTimeInterval:1.0f];
// 模擬獲取到圖像
UIImage *image = [UIImage imageNamed:@"頭像1"];
// 設置圖像,在主線程隊列中設置
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_imageView.image = image;
}];
}];
}
//invocation和blockOperation區別就是一個是用方法調用,一個是代碼塊調用
1.3、NSOperation對象放NSOperationQueue牛逼之處
#pragma mark 依賴關係,可以使子線程按順序執行
- (IBAction)operationDemo3:(id)sender
{
_queue=[[NSOperationQueue alloc]init];
// 1. 下載
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下載 %@" , [NSThread currentThread]);
}];
// 2. 濾鏡
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"濾鏡 %@" , [NSThread currentThread]);
}];
// 3. 顯示
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"更新UI %@" , [NSThread currentThread]);
}];
// 添加操作之間的依賴關係,所謂“依賴”關係,就是等待前一個任務完成後,後一個任務才能啓動
// 依賴關係可以跨線程隊列實現
[op2 addDependency:op1];
[op3 addDependency:op2];
// 提示:在指定依賴關係時,注意不要循環依賴,否則不工作。
//[op1 addDependency:op3];
[_queue addOperation:op1];
[_queue addOperation:op2];
[[NSOperationQueue mainQueue] addOperation:op3];
}
1.4、最大併發線程數量,這是NSOperation獨有功能
- (IBAction)operationDemo4
{
// 控制同時最大併發的線程數量
[_queue setMaxConcurrentOperationCount:2];
for (NSInteger i =0; i <200; i++) {
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
[_queue addOperation:op];
}
}
****************************************************************************************************************************************************************************************************************************************
********************************************************************************************************************
2、GCD演練是基與C語言的框架寫的
- (IBAction)gcdDemo1
{
/**
GCD就是爲了在“多核”上使用多線程技術
1> 要使用GCD,所有的方法都是dispatch開頭的
2> 名詞解釋
global 全局
queue 隊列
async 異步:執行控制不住先後順序
sync 同步:主要用來控制方法的被調用的順序
3> 要執行異步的任務,就在全局隊列中執行即可
dispatch_async 異步執行控制不住先後順序
4> 關於GCD的隊列
全局隊列 dispatch_get_global_queue
參數:優先級 DISPATCH_QUEUE_PRIORITY_DEFAULT
始終是 0
串行隊列
主隊列
5> 異步和同步於方法名無關,與運行所在的隊列有關!
提示:要熟悉隊列於同步、異步的運行節奏,一定需要自己編寫代碼測試!
同步主要用來控制方法的被調用的順序
*/
// 1. 隊列
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 2. 將任務異步(併發)執行
dispatch_sync(queue, ^{
NSLog(@"a->%@", [NSThread currentThread]);//同步在哪個線程,它執行的方法就在哪個線程
});
dispatch_async(queue, ^{
NSLog(@"b->%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
dispatch_sync(queue, ^{
NSLog(@"我哦我哦我->%@", [NSThread currentThread]);
});
//"我哦我哦我"所在的線程就是這個子線程“不不不不不不不不不”所在的線程
NSLog(@"不不不不不不不不不->%@", [NSThread currentThread]);
});
//從GCD回到主線程的時候必須是異步的
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"main - > %@", [NSThread currentThread]);
});//dispatch_sync方法不能在主隊列中調用,因爲這會無限期的阻止線程並會導致你的應用死鎖。所有通過GCD提交到主隊列的任務必須是異步的。
}
2.1#pragma mark 串行隊列,裏面的操作按順序執行
create方法,獲得的是自己新建的線程,所以create需要我們釋放線程(如果是手動管理內存的話)
//dispatch_queue_t用來引導隊列變量
//createQueue 就是一個隊列變量
//dispatch_queue_create是手動創建隊列的方法,兩個參數,第一個參數是這個隊列的名,第二個參數如果寫DISPATCH_QUEUE_SERIAL表示這是一個順序的隊列,這個隊列裏的方法順序執行。如果是DISPATCH_QUEUE_CONCURRENT,表示這是一個並行的隊列,則這個隊列裏的方法同時執行
//create出來的默認爲default優先級
//用完之後,要釋放
//dispatch_release(createQueue);
- (void)makeGCD_Queue
{
//串行隊列自行創建,不能get
dispatch_queue_t queue=dispatch_queue_create("Myqueue",DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
for (int i =0 ;i<1000; i++) {
NSLog(@"1");
}
NSLog(@"a->%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"b->%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
for (int i =0 ;i<1000; i++) {
NSLog(@"2");
}
NSLog(@"c->%@", [NSThread currentThread]);
});
//從GCD回到主線程的時候必須是異步的
dispatch_async(queue, ^{
//必須將這個回到主線程的方法,放在這個隊列中的一個請求方法,纔會按照順序執行
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"d->%@", [NSThread currentThread]);
});//dispatch_sync方法不能在主隊列中調用,因爲這會無限期的阻止線程並會導致你的應用死鎖。所有通過GCD提交到主隊列的任務必須是異步的。
});
}
2.2#pragma mark GCD隊列組,併發執行所有任務,所有任務執行完畢後回主隊列
- (void)makeGCD_Group {
dispatch_group_t group =dispatch_group_create();
dispatch_queue_t queue =dispatch_get_global_queue(0,0);
dispatch_group_async(group, queue, ^{
for (int i =0 ;i<1000; i++) {
NSLog(@"1");
}
NSLog(@"a->%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@“b->%@“, [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
for (int i =0 ;i<1000; i++) {
NSLog(@"2");
}
NSLog(@“c->%@“, [NSThread currentThread]);
});
//Group隊列任務組,併發執行任務組中的任務,全部執行完畢後,再最後用notify告知所有任務完成,並做相應處理
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
NSLog(@“d->%@“, [NSThread currentThread]);
});
}
3、全局隊列和併發隊列的區別:
1、全局隊列沒有名字,但是併發隊列有名字。有名字可以便於查看系統日誌
2、全局隊列是所有應用程序共享的。
3、在mrc的時候,全局隊列不用手動釋放,但是併發隊列需要。