IOS多線程二NSThread簡約而不簡單
今天就來著手教大家在IOS中簡單的實現(xiàn)多線程箱舞。IOS實現(xiàn)多線程的方式有幾種督函,但是要說最容易上手的還是NSThread,在IOS實現(xiàn)多線程的幾種方法中提针,在我看來其實沒有明顯的好壞之分藕甩,只有適合之說施敢,看何種場景下適合使用何種方式。
NSThread相對來說更加輕量級狭莱,并且更加具體僵娃,沒有那么抽象,一個線程就是一個類的對象腋妙。你可以給這個對象附上需要執(zhí)行的內(nèi)容默怨,其實也就是一個方法,可以通過調(diào)用該類的相關方法骤素,控制其啟動匙睹、關閉、暫停等济竹。好吧痕檬,這里就不多說了,下面著重看下NSThread這個類送浊。
直接在Xcode中就可以進入到NSThread類的.h文件中梦谜。可以看到NSThread是一個NSObject類的子類袭景,是IOS開發(fā)的一個重要子框架Foundation框架中的一個類唁桩。進入NSThread類的.h文件可以看到一些NSThread比較常見的方法和屬性。如下所述:
1.NSThread的init方法浴讯。
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullableid)argumentNS_AVAILABLE(10_5,2_0);
該方法主要是用一個目標對象的方法來創(chuàng)建一個多線程NSThread類。其中target參數(shù)傳遞目標對象蔼啦,selector參數(shù)傳遞目標對象的一個方法榆纽,其實就是多線程需要執(zhí)行的內(nèi)容。argument可以傳遞一個臨時參數(shù)到多線程執(zhí)行的方法中捏肢。
2.Start方法
該方法是控制線程啟動執(zhí)行的方法奈籽。init方法創(chuàng)建的NSThread對象,只有調(diào)用該方法才能啟動執(zhí)行鸵赫。
3.detachNewThreadSelector方法
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullableid)argument;
該方法與init方法類似衣屏,參數(shù)也是一樣,區(qū)別就在于辩棒,init方法初始化好一個多線程對象之后狼忱,需要調(diào)用start方法啟動執(zhí)行膨疏,而該方法創(chuàng)建好后直接自己啟動執(zhí)行,不需要再調(diào)用start方法钻弄。并且也不會產(chǎn)生顯示的對象佃却,無法通過對象的方法來控制結(jié)束或者暫停執(zhí)行線程。
4.類方法isMultiThreaded
+ (BOOL)isMultiThreaded;
判斷當前代表執(zhí)行是否在主線程中
5.類方法currentThread
+ (NSThread*)currentThread;
獲取當前線程窘俺。
6.線程暫停方法
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
該方法可傳遞一個秒級別的參數(shù)ti饲帅,來暫停執(zhí)行當前代碼所在的線程ti秒。
7.退出線程方法
+ (void)exit;
該方法是真正可以讓線程退出的方法瘤泪,在某個線程中調(diào)用該方法灶泵,該線程就會直接退出,之后的代碼就不會再執(zhí)行,而且要特別指出对途,該方法如果直接在主線程中調(diào)用的話赦邻,連主線程都會被直接終止哦,主線程如果都被終止了掀宋,那等于整個程序就已經(jīng)失去活力了深纲,APP都會整個卡死。
8 cancle標志方法
- (void)cancelNS_AVAILABLE(10_5,2_0);
@property(readonly,getter=isCancelled)BOOLcancelledNS_AVAILABLE(10_5,2_0);
很多初學者以為cancel就是退出線程劲妙,其實不是湃鹊,這里的cancel其實就是類中的一個BOOL型變量,用戶調(diào)用了cancel方法镣奋,該BOOL型變量就變成了真币呵,再調(diào)用isCancel就可以看到其值是YES還是NO,然后再根據(jù)該標志位做一些工作。所以對比一下退出線程還是要靠exit方法侨颈,或者直接在線程中判斷調(diào)用return退出余赢。
9 設置線程優(yōu)先級
+ (BOOL)setThreadPriority:(double)p;
@propertydoublethreadPriorityNS_AVAILABLE(10_6,4_0);// To be deprecated; use qualityOfService below
通過以上方法可以查看和設置線程優(yōu)先級,優(yōu)先級高的線程會優(yōu)先執(zhí)行哈垢,這里不建議進行此類設置妻柒,會打亂系統(tǒng)之前的線程優(yōu)先級安排≡欧郑可能造成某些底等級的線程卡頓或者長時間得不到執(zhí)行举塔。
以上大致就是NSThread類已經(jīng)類中相關的屬性和方法的基本介紹。下面就講3個具體使用NSThread實現(xiàn)多線程的例子求泰。
1.啟動一個線程
代碼示例
- (void)viewDidLoad?
{
? ? ?[super viewDidLoad];//進入某個viewController時啟動一個線程
? ? ?//使用已經(jīng)寫好的線程執(zhí)行方法FunctionForNSThread初始化一個NSThread類對象
? ? ?NSThread* nowTestThread = [[NSThread alloc] initWithTarget:self selector:@selector(FunctionForNSThread) object:nil];
? ? ?//啟動該線程類對象
? ? ?[nowTestThread start];
}
- (void)FunctionForNSThread
{
? ? ? if([NSThread isMainThread])//使用NSThread類方法isMainThread判斷當前線程是否為主線程
? ? ? {//主線程輸出信息
? ? ? ? ? ? ?NSLog(@"now is in MainThread");
? ? ? }
? ? ? else
? ? ? {//非主線程輸出信息
? ? ? ? ? ? ?NSLog(@"now is not in MainThread");
? ? ? }
}
這里的輸出結(jié)果為
2016-09-20 23:12:25.566 MultiThreadExample[622:15261] now is not in MainThread
說明我們已經(jīng)啟動了另外一個線程央渣。
2.啟動一個循環(huán)執(zhí)行的線程。
- (void)viewDidLoad?
{
? ? ?[super viewDidLoad];//進入某個viewController時啟動一個線程
? ? ?//使用已經(jīng)寫好的線程執(zhí)行方法FunctionForNSThread初始化一個NSThread類對象
? ? ?NSThread* nowTestThread = [[NSThread alloc] initWithTarget:self selector:@selector(FunctionForNSThread) object:nil];
? ? ?//啟動該線程類對象
? ? ?[nowTestThread start];
}
- (void)FunctionForNSThread
{
? ? ? intnowIndex =0;
? ? ? while(YES)//while循環(huán)執(zhí)行
? ? ? {
? ? ? ? ? ?nowIndex++;
? ? ? ? ? ?[NSThread sleepForTimeInterval:1];//每次執(zhí)行到這里讓線程暫停1秒鐘
? ? ? ? ? ?if([NSThread isMainThread])//使用NSThread類方法isMainThread判斷當前線程是否為主線程
? ? ? ? ? ?{//主線程輸出信息
? ? ? ? ? ? ? ? NSLog(@"%d now is in MainThread",nowIndex);
? ? ? ? ? ?}
? ? ? ? ? else
? ? ? ? ? {//非主線程輸出信息
? ? ? ? ? ? ? ? ? NSLog(@"%d now is not in MainThread",nowIndex);
? ? ? ? ? ?}
? ? ? }
}
該段代碼輸出結(jié)果如下:
2016-09-20 23:15:02.010 MultiThreadExample[634:16310] 1 now is not in MainThread
2016-09-20 23:15:03.016 MultiThreadExample[634:16310] 2 now is not in MainThread
2016-09-20 23:15:04.018 MultiThreadExample[634:16310] 3 now is not in MainThread
2016-09-20 23:15:05.021 MultiThreadExample[634:16310] 4 now is not in MainThread
2016-09-20 23:15:06.022 MultiThreadExample[634:16310] 5 now is not in MainThread
2016-09-20 23:15:07.023 MultiThreadExample[634:16310] 6 now is not in MainThread
2016-09-20 23:15:08.024 MultiThreadExample[634:16310] 7 now is not in MainThread
2016-09-20 23:15:09.025 MultiThreadExample[634:16310] 8 now is not in MainThread
2016-09-20 23:15:10.026 MultiThreadExample[634:16310] 9 now is not in MainThread
………
如果不強行終止程序渴频,該線程會一直執(zhí)行下去芽丹,數(shù)字編碼也會從1開始一直不斷增大。
還有一點我們在線程中使用[NSThreadsleepForTimeInterval:1];方法每次循環(huán)開始時讓線程暫停1秒鐘卜朗,大家一定要注意拔第,在這種循環(huán)執(zhí)行的線程中咕村,一定要設置循環(huán)停止時間,否則線程不斷死循環(huán)就會將設備CPU徹底占用楼肪,如果你運行的設備是雙核CPU培廓,你啟動一個不設置循環(huán)停止時間的線程,就會直接將其中一個CPU全部沾滿卡死春叫。
從上述輸出結(jié)果中也可以看到肩钠,每次輸出間隔時間都是1秒鐘。也就是說該循環(huán)執(zhí)行的內(nèi)容每隔1秒執(zhí)行一次暂殖。
3.終止一個線程
停止一個線程有很多方法价匠,初學者常犯的一個錯誤就是調(diào)用NSThread類的cancel方法。時機調(diào)用該方法并沒有作用呛每,該方法中設置的cancel只是一個標記位踩窖,調(diào)用cancel方法之后,再通過iscancel方法獲取該標記位就可以得到是否已經(jīng)cancel晨横,真正的cancel需要在該線程的執(zhí)行方法體中調(diào)用類方法exit來真正退出該線程洋腮。
- (void)viewDidLoad?
{
? ? ? [super viewDidLoad];//進入某個viewController時啟動一個線程
? ? ? //使用已經(jīng)寫好的線程執(zhí)行方法FunctionForNSThread初始化一個NSThread類對象
? ? ? NSThread* nowTestThread = [[NSThread alloc] initWithTarget:self selector:@selector(FunctionForNSThread) object:nil];
? ? ? //啟動該線程類對象
? ? ? [nowTestThread start];
? ? ? [NSThread sleepForTimeInterval:10];//主線程暫停執(zhí)行10秒鐘,這里測試需要手形,一般不建議暫停主線程啥供。
? ? ? [nowTestThread cancel];
}
- (void)FunctionForNSThread
{
? ? ? intnowIndex =0;
? ? ? while(YES)//while循環(huán)執(zhí)行
? ? ? {
? ? ? ? ? ? nowIndex++;
? ? ? ? ? ? [NSThread sleepForTimeInterval:1];//每次執(zhí)行到這里讓線程暫停1秒鐘
? ? ? ? ? ? if([NSThread isMainThread])//使用NSThread類方法isMainThread判斷當前線程是否為主線程
? ? ? ? ? ? {//主線程輸出信息
? ? ? ? ? ? ? ? ?NSLog(@"%d now is in MainThread",nowIndex);
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {//非主線程輸出信息
? ? ? ? ? ? ? ? ?NSLog(@"%d now is not in MainThread",nowIndex);
? ? ? ? ? ? }
? ? ? ? ? ?if([[NSThread currentThread] isCancelled])//先通過currentThread方法獲取當前線程,再通過isCancelled方法獲取cancel標志位
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?NSLog(@"退出線程之前");
? ? ? ? ? ? ? ? ?[NSThread exit];//cancel標志位為真库糠,說明線程外部已經(jīng)發(fā)出了終止線程的標志信號伙狐,在本線程調(diào)用exit停止線程。
? ? ? ? ? ? ? ? ?NSLog(@"退出線程之后");//該log永遠不會被打印瞬欧,因為在exit方法之后的代碼都不會再執(zhí)行
? ? ? ? ? ?}
? ? ? }
}
該段代碼執(zhí)行結(jié)果如下:
2016-09-20 23:28:37.258 MultiThreadExample[675:21235] 1 now is not in MainThread
2016-09-20 23:28:38.265 MultiThreadExample[675:21235] 2 now is not in MainThread
2016-09-20 23:28:39.267 MultiThreadExample[675:21235] 3 now is not in MainThread
2016-09-20 23:28:40.272 MultiThreadExample[675:21235] 4 now is not in MainThread
2016-09-20 23:28:41.277 MultiThreadExample[675:21235] 5 now is not in MainThread
2016-09-20 23:28:42.281 MultiThreadExample[675:21235] 6 now is not in MainThread
2016-09-20 23:28:43.283 MultiThreadExample[675:21235] 7 now is not in MainThread
2016-09-20 23:28:44.288 MultiThreadExample[675:21235] 8 now is not in MainThread
2016-09-20 23:28:45.294 MultiThreadExample[675:21235] 9 now is not in MainThread
2016-09-20 23:28:46.312 MultiThreadExample[675:21235] 10 now is not in MainThread
2016-09-20 23:28:46.312 MultiThreadExample[675:21235]退出線程之前
因為主線程在暫停10秒之后將之前啟動的線程cancel標志置為YES贷屎,而在線程內(nèi)部每次循環(huán)都會判斷cancel標志位,如果為真就調(diào)用exit退出線程艘虎,而每次循環(huán)間隔為1秒唉侄,所以執(zhí)行10次之后線程就退出了。
另外exit之后的代碼都不會被執(zhí)行野建,所以“退出線程之后”log沒有打印属划。
以上就是IOS多線程實現(xiàn)方案之一 NSThread的相關內(nèi)容,如果大家有什么心得或者不同見解可以找我溝通贬墩,QQ 1828141617 ? 郵箱 yimaoruanjian@126.com