子線程搞事情,主線程來顯示
我們都知道把UI相關(guān)的事情放在主線程,但是如果當(dāng)我們要下載一張比較大的圖片來顯示的話,勢(shì)必會(huì)是一個(gè)耗時(shí)的操作,如果將其放在主線程操作,那么必然會(huì)對(duì)主線程造成阻塞,那么我們就需要將它放在子線程中去搞,搞完了再到主線程中去顯示UI.這也是我們最常使用GCD的地方了
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"我在子線程!開始我的耗時(shí)操作吧,我是不會(huì)阻塞主線程的");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"事情搞完了回到主線程做事吧");
});
});
隊(duì)列幫你搞事情
串行隊(duì)列
接下來假設(shè)一個(gè)場(chǎng)景,在一個(gè)詳情頁中,需要先請(qǐng)求到詳情數(shù)據(jù),再通過詳情數(shù)據(jù)中的某個(gè)參數(shù)去請(qǐng)求評(píng)論列表,哇!是不是有點(diǎn)炸~
這個(gè)時(shí)候我們是不是想做一件事情,先去搞詳情數(shù)據(jù),等詳情數(shù)據(jù)搞到手了,再去搞評(píng)論列表的數(shù)據(jù).于是,我們這里可以搞一個(gè)串行隊(duì)列幫我們.因?yàn)闆]有真實(shí)數(shù)據(jù),所以用圖片下載代替說明一下串行隊(duì)列.
//圖片數(shù)據(jù)
static NSString * const picUrlOne = @"http://b.hiphotos.baidu.com/image/pic/item/0823dd54564e925838c205c89982d158ccbf4e26.jpg";
static NSString * const picUrlTwo = @"http://e.hiphotos.baidu.com/image/pic/item/d1160924ab18972bf05282ece3cd7b899e510aaf.jpg";
static NSString * const picUrlThree = @"http://c.hiphotos.baidu.com/image/pic/item/58ee3d6d55fbb2fb3943da344a4a20a44623dca8.jpg";
static NSString * const picUrlFour = @"http://e.hiphotos.baidu.com/image/pic/item/1ad5ad6eddc451da9dd88ecdb3fd5266d01632ed.jpg";
- (void)loadImagesBySerial
{
//step one:創(chuàng)建一個(gè)串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("dispatch.serial", DISPATCH_QUEUE_SERIAL);
//step two:講我們要做的事情分別加入到隊(duì)列里面
[self loadImageByDispatch:serialQueue threadcomplete:^{
NSLog(@"image1StartDownLoad");
_imageData1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlOne]]];
} complete:^{
_imageOne.image = _imageData1;
NSLog(@"image1DownLoadOver");
}];
[self loadImageByDispatch:serialQueue threadcomplete:^{
NSLog(@"image2StartDownLoad");
_imageData2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlTwo]]];
} complete:^{
_imageTwo.image = _imageData2;
NSLog(@"image2DownLoadOver");
}];
[self loadImageByDispatch:serialQueue threadcomplete:^{
NSLog(@"image3StartDownLoad");
//故意搞一個(gè)延遲,證明當(dāng)遇到耗時(shí)的情況,任務(wù)4會(huì)等到任務(wù)3完成才執(zhí)行
[NSThread sleepForTimeInterval:3];
_imageData3 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlThree]]];
} complete:^{
_imageThree.image = _imageData1;
NSLog(@"image3DownLoadOver");
}];
[self loadImageByDispatch:serialQueue threadcomplete:^{
NSLog(@"image4StartDownLoad");
_imageData4 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlFour]]];
//step three:任務(wù)至此,所有耗時(shí)操作都已在子線程完成
} complete:^{
_imageFour.image = _imageData1;
NSLog(@"image4DownLoadOver");
//step four:當(dāng)我們最后一個(gè)任務(wù)完成,即可在主線程搞事情了~我們甚至可以將所有的圖片顯示放在這個(gè)位置,讓他們一起顯示出來
/*
_imageOne.image = _imageData1;
_imageTwo.image = _imageData2;
_imageThree.image = _imageData3;
_imageFour.image = _imageData4;
*/
}];
}
- (void)loadImageByDispatch:(dispatch_queue_t)queue threadcomplete:(void(^)())threadComplete complete:(void(^)())complete
{
dispatch_async(queue, ^{
if (threadComplete) {
threadComplete();
}
dispatch_async(dispatch_get_main_queue(), ^{
if (complete) {
complete();
}
});
});
}
并行隊(duì)列
再來搞個(gè)事兒,比如:我們現(xiàn)在有一大堆數(shù)據(jù)要處理,顯然是耗時(shí)的,不能去阻塞主線程吧~那好,現(xiàn)在子線程你得幫我搞事情,那么問題來了,我需要在頁面顯示來自4個(gè)不同模塊的數(shù)據(jù),且這些數(shù)據(jù)處理都是耗時(shí)的,那么并行隊(duì)列就可以出來搞搞事情了,還是用上面下載圖片的例子來說明一下并行隊(duì)列
- (void)loadImagesByConcurrent
{
//step one:創(chuàng)建一個(gè)并行隊(duì)列
dispatch_queue_t concurrentQueue = dispatch_queue_create("dispatch_concurrent", DISPATCH_QUEUE_CONCURRENT);
//step two:開始我們要執(zhí)行的4個(gè)任務(wù)
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
NSLog(@"image1StartDownLoad");
_imageData1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlOne]]];
} complete:^{
_imageOne.image = _imageData1;
NSLog(@"image1DownLoadOver");
}];
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
NSLog(@"image2StartDownLoad");
_imageData2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlTwo]]];
} complete:^{
_imageTwo.image = _imageData2;
NSLog(@"image2DownLoadOver");
}];
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
NSLog(@"image3StartDownLoad");
[NSThread sleepForTimeInterval:3];
_imageData3 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlThree]]];
} complete:^{
_imageThree.image = _imageData1;
NSLog(@"image3DownLoadOver");
}];
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
NSLog(@"image4StartDownLoad");
_imageData4 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlFour]]];
} complete:^{
_imageFour.image = _imageData1;
NSLog(@"image4DownLoadOver");
}];
}
至此,你會(huì)發(fā)現(xiàn)我們的4個(gè)任務(wù)是幾乎同時(shí)開始的,至于期間某個(gè)任務(wù)有阻塞,我們管不了,最終的哪個(gè)先結(jié)束我們也不知道所以我們看到的結(jié)果也是分別顯示的這就有點(diǎn)意思了,如果我們需要拿到所有結(jié)果一起來顯示,又該咋辦呢~~這個(gè)時(shí)候我們就需要dispatch_group這個(gè)東西幫忙了
還是上面下載圖片的例子~
- (void)groupEnterAndLeave
{
//step one:創(chuàng)建一個(gè)并行隊(duì)列
dispatch_queue_t concurrentQueue = dispatch_queue_create("dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT);
//step two:再來一個(gè)組
dispatch_group_t concurrentGroup = dispatch_group_create();
/**
dispatch_group_enter,dispatch_group_leave成對(duì)出現(xiàn)~~~
*/
dispatch_group_enter(concurrentGroup);
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
_imageData1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlOne]]];
dispatch_group_leave(concurrentGroup);
} complete:^{
}];
dispatch_group_enter(concurrentGroup);
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
_imageData2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlTwo]]];
dispatch_group_leave(concurrentGroup);
} complete:^{
}];
dispatch_group_enter(concurrentGroup);
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
_imageData3 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlThree]]];
dispatch_group_leave(concurrentGroup);
} complete:^{
}];
dispatch_group_enter(concurrentGroup);
[self loadImageByDispatch:concurrentQueue threadcomplete:^{
_imageData4 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:picUrlFour]]];
dispatch_group_leave(concurrentGroup);
} complete:^{
}];
//step three:所有任務(wù)完成,收到通知~
dispatch_group_notify(concurrentGroup, concurrentQueue, ^{
NSLog(@"AllTaskOver");
dispatch_async(dispatch_get_main_queue(), ^{
_imageOne.image = _imageData1;
_imageTwo.image = _imageData2;
_imageThree.image = _imageData3;
_imageFour.image = _imageData4;
});
});
}
除了單例,還能這樣玩
比如只希望在整個(gè)工程的生命周期內(nèi),只執(zhí)行一次某段代碼,可以這樣玩兒
static dispatch_once_t once;
dispatch_once(&once, ^{
/**
這里是只想執(zhí)行一次的代碼
*/
});
延時(shí)執(zhí)行
/**
第一個(gè)參數(shù)表示延時(shí)時(shí)間,第二個(gè)參數(shù)是在哪個(gè)隊(duì)列執(zhí)行
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
//需要做的延時(shí)操作
});
零零星星寫了一些,還有很多沒有寫,具體在實(shí)戰(zhàn)中遇到的坑之后再寫,暫時(shí)就這樣.