iOS多線程實現——NSThread的簡單使用

關于iOS多線程的實現方式有多種,今天來共同學習一下NSThread的簡單使用,有疏忽的地方,還望各位不吝賜教。


一、NSThread初始化

// 1、創建線程?

/**
* 第一種方式創建線程
* 參數說明
* 第一個參數:目標對象 self
* 第二個參數:方法選擇器 調用的方法
* 第三個參數:調用方法需要傳遞的參數 (進行賦值后可以在run:方法中當做參數接收)
*/

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(open:) object:@"創建線程"];

// 2、對線程可以進行命名。

thread.name = @"線程名稱,以示區分";

// 3、線程優先級,范圍是0.0-1.0 數字越大,被執行到的可能性越大,只是可能性不代表一定會被執行。

thread.threadPriority = 0.5;

// 4、開啟線程

[thread start];

// 5、實現調用的方法

- (void)open:(NSString *)param{

//? [NSThread currentThread]? 此方法可以獲得當前線程

//? [NSThread mainThread]? 此方法可以獲得主線程

??? NSLog(@"%@---------%@",param,[NSThread currentThread]);

}

// 打印: 創建線程---------{number = 3, name = 線程名稱,以示區分}

/**

* 第二種方式創建線程

* 參數說明

* 第一個參數:方法選擇器 調用的方法

* 第二個參數:目標對象 self

* 第三個參數:調用方法需要傳遞的參數 (進行賦值后可以在run:方法中當做參數接收)

*/

// 1、此方法沒有返回值 相當于創建并啟動線程

[NSThread detachNewThreadSelector:@selector(open:) toTarget:self withObject:@"分離子線程"];

// 2、實現調用的方法

- (void)open:(NSString *)param{

?? NSLog(@"%@---------%@",param,[NSThread currentThread]);

}

// 打印:分離子線程---------{number = 3, name = (null)}

/**

* 第三種方式創建線程

* 參數說明

* 第一個參數:方法選擇器 調用的方法

* 第二個參數:調用方法需要傳遞的參數 (進行賦值后可以在run:方法中當做參數接收)

*/

// 1、此方法沒有返回值 隱式創建并啟動線程

[self performSelectorInBackground:@selector(open:) withObject:@"開啟后臺線程"];

// 2、實現調用的方法

- (void)open:(NSString *)param{

?? NSLog(@"%@---------%@",param,[NSThread currentThread]);

}

// 打印:開啟后臺線程---------{number = 3, name = (null)}

二、暫停當前線程

/**

* 暫停當前線程(阻塞)方式一

* 此方法代表讓當前線程休眠兩秒后再進行其他操作

*/

[NSThread sleepForTimeInterval:2.0];

/**

* 暫停當前線程(阻塞)方式二

* 此方法代表讓當前線程休眠兩秒后再進行其他操作

*/

[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

三、退出當前線程

/**

* 退出當前線程

* 此方法代表強制退出當前線程

*/

[NSThread exit];

四、線程之間的通信

/**

*? 關于線程之間的通信的說明:

*? 1、主線程是專門用來進行更新UI和處理用戶事件的線程,一般耗時操作放在子線程中執行。

*? 2、當子線程將任務完成后,需要和主線程進行通信,將獲取的數據展示到UI中,以便和用戶進行交互。?

*?? 在此使用一個例子來進行說明:在子線程中下載一張圖片,然后在主線程中進行展示。

*/

// 1、使用第二種方式創建線程

? [NSThread detachNewThreadSelector:@selector(downloadImage) toTarget:self withObject:nil];

// 2、進行downloadImage方法的實現

- (void)downloadImage{

// 2.1、確定圖片的URL地址

??? NSURL *url = [NSURL URLWithString:@"此處需要圖片的URL地址"];

// 2.2、根據圖片的URL地址下載圖片二進制數據到本地

??? NSData *data = [NSData dataWithContentsOfURL:url];

// 2.3、轉換圖片格式 將二進制數據轉換為圖片數據

??? UIImage *image = [UIImage imageWithData:data];

??? NSLog(@"downloadImage-----%@",[NSThread currentThread]);

// 2.4、將圖片數據交給主線程顯示圖片 以下三種方式任選一種即可

/**

* 與主線程通信的方式一

* 第一個參數:回到主線程調用哪個方法

* 第二個參數:前面方法要傳遞的參數

* 第三個參數:是否等待 如果等待相當于當前方法為阻塞狀態,end的打印會在圖片顯示方法執行完后進行打印

*/

?[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];

/**

* 與主線程通信的方式二

* 第一個參數:回到主線程調用哪個方法

* 第二個參數:指定哪個線程執行showImage:的方法(本方法相比于方式一可以指定線程執行)

* 第三個參數:前面方法要傳遞的參數

* 第四個參數:是否等待 如果等待相當于當前方法為阻塞狀態,end的打印會在圖片顯示方法執行完后進行打印

*/

?[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];

NSLog(@"end-------------------------end");

}

// 3、顯示圖片的方法

- (void)showImage:(UIImage *)image{

?? // 打印當前線程信息

? ? NSLog(@"showImage-----%@",[NSThread currentThread]);

?? // 顯示圖片

?? self.iconImageView.image = image;

}

/**

* 與主線程通信的方式三

* 說明:

* 1、使用此方法可以省略以上顯示圖片的方法,故而寫在這里,此代碼與以上建立與主線程通信代碼書寫的位置相同;

* 2、因為在此案例中是直接在UIImageView中進行圖片賦值,所以本方法具有特殊性。

* 3、可以使用的原因是因為performSelector:onThread:方法是在NSObject的分類中,所以只要是對象就可以進行調用。

*/

[self.iconImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

五、線程的聲明周期

當線程中的任務執行完畢后才會釋放,并不會因為它是一個局部變量,在出了作用域后就被釋放。

關于線程的狀態的聲明:

1、New(創建)

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(open:) object:@"創建線程"]; // 此代碼執行完畢后會在內存中創建一個線程對象。

2、Runnable(就緒狀態)

[thread start]; // 線程對象進入就緒狀態,并放入可調度線程池中,只有在可調度線程池中的線程對象才可以被系統調度。

3、Running(運行狀態)

當線程對象被系統調度時就處在運行狀態,在系統調度其他線程的時候,就進入就緒狀態。

4、Blocked(阻塞狀態)

在調用sleep等方法的時候,線程會進入阻塞狀態。線程對象會被從可調度線程池中移除出來,這個時候線程對象還在內存中存在,但是系統不會調度這個線程對象。

當然了,當sleep的設置時間到了以后,會再從內存中將線程對象放入可調度線程池中,線程對象會再進入就緒狀態。

5、Dead(死亡狀態)

當線程對象把任務執行完畢或者被強制退出,則進入死亡狀態。這個時候內存中線程對象被銷毀,內存中已經沒有此線程對象了。


六、自定義NSThread

/**

* 說明

* 1、 關于自定義的NSThread創建線程的方式可以使用allac init 進行創建;

*? 2、在自定義NSThread的.m文件中實現main方法,寫在這里就可以實現自定義NSThread執行指定的任務;

* 3、當查看其它工程的源碼,發現NSThread創建線程的方式是以下方式,則方便查找相關任務的執行代碼。

*/

//? 1、進行線程的創建

GHThread *thread = [[GHThread alloc] init];

//? 2、開啟線程

[thread start];

// 3、在GHThread.m中實現main方法

- (void)main{

??? NSLog(@"end---------%@",[NSThread currentThread]);

}

// 打印:end---------{number = 5, name = (null)}


寫在最后的話:關于NSThread雖然簡單易用,可以直接操作線程對象,但是線程的生命周期需要手動管理,使用頻率不是很高。關于iOS多線程的其他實現方式會在以后繼續學習和分享。。。。。。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容