Swift3.0 中的 Thread 類
其實就是 NSThread
import CoreFoundation
import CoreGraphics
import Darwin
import Darwin.uuid
import Foundation
/* NSThread.h
Copyright (c) 1994-2015, Apple Inc. All rights reserved.
*/
// 在 swift 3.0 中 NSThread 被修改我 Thread
public class Thread : NSObject {
// 獲取當(dāng)前執(zhí)行的線程
// 通過當(dāng)前線程的 number 屬性, number == 1 的時候為單線程, number > 1 的時候是多線程, number 的數(shù)字沒有很多的參考價值
public class func current() -> Thread
// 分離出新線程, 類方法, (直接創(chuàng)建一個線程對象,并開啟線程)
// 當(dāng)我們給需要在新線程中執(zhí)行某方法的時候可以用這個方法
public class func detachNewThreadSelector(_ selector: Selector, toTarget target: AnyObject, with argument: AnyObject?)
// 判斷是否是多線程
public class func isMultiThreaded() -> Bool
public var threadDictionary: NSMutableDictionary { get }
// 線程睡(指定時間)
public class func sleep(until date: Date)
// 指定時間間隔
public class func sleep(forTimeInterval ti: TimeInterval)
// 退出線程
public class func exit()
// 線程的優(yōu)先級處理
// 線程的級別
public class func threadPriority() -> Double
// 設(shè)置線程級別
public class func setThreadPriority(_ p: Double) -> Bool
@available(iOS 4.0, *)
// 設(shè)置線程的級別孩锡, 已經(jīng)被棄用酷宵,請用下面的服務(wù)質(zhì)量
public var threadPriority: Double // To be deprecated; use qualityOfService below
@available(iOS 8.0, *)
// 服務(wù)質(zhì)量
public var qualityOfService: QualityOfService // read-only after the thread is started
@available(iOS 2.0, *)
// 調(diào)用堆棧返回的地址
public class func callStackReturnAddresses() -> [NSNumber]
@available(iOS 4.0, *)
// 線程的符號
public class func callStackSymbols() -> [String]
@available(iOS 2.0, *)
// 線程名稱
public var name: String?
@available(iOS 2.0, *)
// 獲取棧內(nèi)存大小 , 默認(rèn) 512k
public var stackSize: Int
@available(iOS 2.0, *)
// 判斷是否是主線程
public var isMainThread: Bool { get }
@available(iOS 2.0, *)
// 判斷當(dāng)前線程是否是主線程
public class func isMainThread() -> Bool // reports whether current thread is main
@available(iOS 2.0, *)
// 獲取主線程
public class func main() -> Thread
@available(iOS 2.0, *)
// 初始化方法
public init()
@available(iOS 2.0, *)
// 便利初始化方法
public convenience init(target: AnyObject, selector: Selector, object argument: AnyObject?)
// 線程狀態(tài)的判斷
@available(iOS 2.0, *)
// 線程是否執(zhí)行
public var isExecuting: Bool { get }
@available(iOS 2.0, *)
// 線程是否完成
public var isFinished: Bool { get }
@available(iOS 2.0, *)
// 線程是否取消
public var isCancelled: Bool { get }
@available(iOS 2.0, *)
// 取消線程
public func cancel()
@available(iOS 2.0, *)
// 開始線程
public func start()
@available(iOS 2.0, *)
// 線程主體方法躬窜,這個方法一般是用來重寫的
public func main() // thread body method
}
// 通知
extension NSNotification.Name {
// 將要變成多線程
public static let NSWillBecomeMultiThreaded: NSNotification.Name
// 已經(jīng)變成單線程
public static let NSDidBecomeSingleThreaded: NSNotification.Name
// 線程將要推出
public static let NSThreadWillExit: NSNotification.Name
}
// NSObject 的類擴展
// 意味著所有的 NSObject 對象都可以使用下面的方法
extension NSObject {
// 在主線程執(zhí)行某方法
public func performSelector(onMainThread aSelector: Selector, with arg: AnyObject?, waitUntilDone wait: Bool, modes array: [String]?)
// 在主線程執(zhí)行某方法
public func performSelector(onMainThread aSelector: Selector, with arg: AnyObject?, waitUntilDone wait: Bool)
@available(iOS 2.0, *)
// 在某個線程執(zhí)行某方法
public func perform(_ aSelector: Selector, on thr: Thread, with arg: AnyObject?, waitUntilDone wait: Bool, modes array: [String]?)
@available(iOS 2.0, *)
// 在某個線程執(zhí)行某方法
public func perform(_ aSelector: Selector, on thr: Thread, with arg: AnyObject?, waitUntilDone wait: Bool)
@available(iOS 2.0, *)
// 在后頭執(zhí)行選中的方法
public func performSelector(inBackground aSelector: Selector, with arg: AnyObject?)
}
上面貼頭文件純屬個人喜好浇垦,本人簡單翻譯為的是后期的被查,解決英文不好的毛病荣挨。
1男韧、判斷當(dāng)前線程數(shù)可以知道是否是多線程朴摊。
Thread.current()
number 為 1 的時候是主線程,線程數(shù)不為1 就為多線程此虑。數(shù)子沒有意義甚纲。
print(Thread.current())
打印結(jié)果
<NSThread: 0x7ff791402120>{number = 1, name = main}
objc
[NSThread currentThread];
NSLog(@"%@", [NSThread currentThread]);
打印結(jié)果:
2016-06-21 19:28:24.644 Thread-Objc[4072:1165465] <NSThread: 0x7f9e73405100>{number = 1, name = main}
使用函數(shù)判斷是否是多線程
if Thread.isMultiThreaded() {
print("是單線程執(zhí)行")
}
objc
if (![NSThread isMultiThreaded]) {
NSLog(@"中是單線程!");
}
2朦前、線程的創(chuàng)建
// 創(chuàng)建一個線程對象
let thread1 = Thread(target: self, selector: #selector(longOperation), object: "thread1")
// 線程默認(rèn)是不會啟動的
// 必須我們手動啟動
thread1.start()
// 線程執(zhí)行的的方法
func longOperation(sender: AnyObject){
print(sender) // sender == thread1
for i in 0...50000 {
print("\(i )" + "\(Thread.current())")
}
}
objc
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(longOperation:) object:@"newThread"];
[thread start];
- (void)longOperation:(NSObject *)sender {
NSLog(@"%@", sender); // sender == newThread
NSLog(@"%@", [NSThread currentThread]);
}
// 這樣就創(chuàng)建了一個線程對象
// 這樣創(chuàng)建的線程操作性太小
// 我們一般會使用上面的方法
let thread = Thread()
通過 Thread 直接分離(創(chuàng)建)一個線程執(zhí)行某個方法介杆。
使用這種方式創(chuàng)建的線程,線程是直接啟動的
Thread.detachNewThreadSelector(#selector(longOperation), toTarget: self, with: "newThread")
// 線程執(zhí)行的方法
func longOperation(sender: AnyObject){
print(sender) // sender == newThread
for i in 0...50 {
print("\(i )" + "\(Thread.current())")
}
}
[NSThread detachNewThreadSelector:@selector(longOperation:) toTarget:self withObject:@"newThread"];
- (void)longOperation:(NSObject *)sender {
NSLog(@"%@", sender); // sender == newThread
NSLog(@"%@", [NSThread currentThread]);
}
打印結(jié)果
2016-06-21 19:46:56.170 Thread-Objc[4351:1183028] newThread
2016-06-21 19:46:56.171 Thread-Objc[4351:1183028] <NSThread: 0x7f80e2c7a7b0>{number = 2, name = (null)}
一個方法里面的內(nèi)容只能在一個線程里面執(zhí)行韭寸,block 或閉包除外春哨。
使用 NSObject 的方法直接在后臺線程執(zhí)行某方法
(實際上也是創(chuàng)建一個新的線程對象,并啟動線程)
self.performSelector(inBackground: #selector(longOperation), with: "newThread")
// 線程執(zhí)行的方法
func longOperation(sender: AnyObject){
print(sender)
for i in 0...50 {
print("\(i )" + "\(Thread.current())")
}
}
[self performSelectorInBackground:@selector(longOperation:) withObject:@"newThread"];
- (void)longOperation:(NSObject *)sender {
NSLog(@"%@", sender); // sender == newThread
NSLog(@"%@", [NSThread currentThread]);
}
打印結(jié)果
2016-06-21 19:46:56.170 Thread-Objc[4351:1183028] newThread
2016-06-21 19:46:56.171 Thread-Objc[4351:1183028] <NSThread: 0x7f80e2c7a7b0>{number = 2, name = (null)}
這種方式表明:
任何 NSObject 對象都可以開啟子線程恩伺。(都具有開啟線程的能力)
3赴背、線程屬性
線程名稱
// 線程名稱
public var name: String?
線程的名稱通常在大的商業(yè)應(yīng)用中,希望應(yīng)用程序上架后晶渠,捕獲到用戶使用崩潰的一些場景凰荚。
如果知道程序在哪個線程中崩潰,能夠輔助排錯乱陡。
如果線程非常多浇揩,而且在調(diào)試的時候可以起到輔助作用。
線程堆棧大小
Thread.current().stackSize
// 調(diào)整大小
Thread.current().stackSize = 1024 * 1024
線程的椇┑撸空間大小是 統(tǒng)一都是 512 k胳徽, 大小是可以修改。
在以前的版本中 主線程是 1024k爽彤, 其他線程是 512k 养盗,大小是不能修改。
線程的優(yōu)先級
// 線程的優(yōu)先級 0 到1.0 适篙, 1 的優(yōu)先級最高往核。
// 默認(rèn)的線程優(yōu)先級是 0.5
Thread.current().threadPriority
線程的優(yōu)先級一般不需要修改。線程的優(yōu)先級不一定決定線程的執(zhí)行循序嚷节。
(經(jīng)典例子:優(yōu)先級反轉(zhuǎn))
優(yōu)先級高只能說明 cpu 在調(diào)度的時候回優(yōu)先調(diào)度聂儒,并不意味著,優(yōu)先級低的就不會調(diào)度硫痰。
多線程開發(fā)注意
- 優(yōu)先級只能說明 cpu 優(yōu)先調(diào)度衩婚,并不意味著優(yōu)先級低的不調(diào)度。(不要改優(yōu)先級)
- 不能相信一次執(zhí)行的結(jié)果效斑。
- 不要去做不同線程的比較非春。
葵花寶典:
多線程開發(fā)一定要簡單。(越復(fù)雜越不可控)
4、線程間通訊 (重點中的重點)
在子線程進(jìn)行耗時操作奇昙,在子線程完成后护侮,根據(jù)子線程的執(zhí)行結(jié)果刷新UI界面。
(有的時候储耐,不在主線程更新 UI 也不會有問題羊初。 但是一定要在主線程更新 UI)
/**
#selector(refresUI) : 調(diào)用的方法
with: nil 要傳遞到主線程的參數(shù)。我這里傳的是 nil 表示不傳參數(shù)弧岳。
waitUntilDone : true 等待主線程方法執(zhí)行完畢
false 不等待主線程方法執(zhí)行完畢
(說白了就是線程的串行和并行的問題凳忙, 為 true 的是線程串行业踏, false 為并行 )
*/
self.performSelector(onMainThread: #selector(refresUI), with: nil, waitUntilDone: true)
第一種創(chuàng)建線程的方式
print("befor -\(Thread.current())")
// 1. thread 對象, 在子線程中執(zhí)行耗時操作
let thread = Thread(target: self, selector: #selector(longOperation), object: nil)
// 2. 啟動線程
thread.start()
print("after -\(Thread.current())")
// 耗時操作
func longOperation(sender: AnyObject){
// 模擬的耗時操作
print("longOperation -\(Thread.current())")
// object 參數(shù)對象可以用來進(jìn)行線程之間傳值
self.performSelector(onMainThread: #selector(refresUI), with: nil, waitUntilDone: false)
}
// 刷新界面
func refresUI(){
print("refresUI -\(Thread.current())")
}
// 打印結(jié)果
befor -<NSThread: 0x7fb0b2c059b0>{number = 1, name = main}
after -<NSThread: 0x7fb0b2c059b0>{number = 1, name = main}
longOperation -<NSThread: 0x7fb0b2f06610>{number = 3, name = (null)}
refresUI -<NSThread: 0x7fb0b2c059b0>{number = 1, name = main}
耗時操作是在子線程執(zhí)行的,刷新 ui 是在主線程執(zhí)行的
分離線程的方式
進(jìn)行了線程之間的傳值
print("befor -\(Thread.current())")
Thread.detachNewThreadSelector(#selector(longOperation), toTarget: self, with: "detachNewThread")
print("after -\(Thread.current())")
// 耗時操作
func longOperation(sender: AnyObject){
// 模擬的耗時操作
print("longOperation -\(Thread.current()) + 線程之間的傳遞的值:\(sender)")
self.performSelector(onMainThread: #selector(refresUI), with: sender, waitUntilDone: false)
}
// 刷新界面
func refresUI(sender: AnyObject){
print("refresUI -\(Thread.current()) + 線程之間的傳遞的值:\(sender)")
}
// 打印的結(jié)果
befor -<NSThread: 0x7ff3e2d06550>{number = 1, name = main}
after -<NSThread: 0x7ff3e2d06550>{number = 1, name = main}
longOperation -<NSThread: 0x7ff3e2d1e440>{number = 3, name = (null)} + 線程之間的傳遞的值:detachNewThread
refresUI -<NSThread: 0x7ff3e2d06550>{number = 1, name = main} + 線程之間的傳遞的值:detachNewThread
用 NSObject 執(zhí)行后臺線程
(我個人比較喜歡這種方式)
print("befor -\(Thread.current())")
self.performSelector(inBackground: #selector(longOperation), with: "inBackgroundThread")
print("after -\(Thread.current())")
// 耗時操作
func longOperation(sender: AnyObject){
// 模擬的耗時操作
print("longOperation -\(Thread.current()) + 線程之間的傳遞的值:\(sender)")
self.performSelector(onMainThread: #selector(refresUI), with: sender, waitUntilDone: false)
}
// 刷新界面
func refresUI(sender: AnyObject){
print("refresUI -\(Thread.current()) + 線程之間的傳遞的值:\(sender)")
}
打印結(jié)果
befor -<NSThread: 0x7f9c6ad078b0>{number = 1, name = main}
after -<NSThread: 0x7f9c6ad078b0>{number = 1, name = main}
longOperation -<NSThread: 0x7f9c6d415d90>{number = 3, name = (null)} + 線程之間的傳遞的值:inBackgroundThread
refresUI -<NSThread: 0x7f9c6ad078b0>{number = 1, name = main} + 線程之間的傳遞的值:inBackgroundThread