Swift3.0 中的 Thread 類
其實(shí)就是 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í)行的線程
// 通過(guò)當(dāng)前線程的 number 屬性, number == 1 的時(shí)候?yàn)閱尉€程, number > 1 的時(shí)候是多線程, number 的數(shù)字沒(méi)有很多的參考價(jià)值
public class func current() -> Thread
// 分離出新線程, 類方法, (直接創(chuàng)建一個(gè)線程對(duì)象,并開(kāi)啟線程)
// 當(dāng)我們給需要在新線程中執(zhí)行某方法的時(shí)候可以用這個(gè)方法
public class func detachNewThreadSelector(_ selector: Selector, toTarget target: AnyObject, with argument: AnyObject?)
// 判斷是否是多線程
public class func isMultiThreaded() -> Bool
public var threadDictionary: NSMutableDictionary { get }
// 線程睡(指定時(shí)間)
public class func sleep(until date: Date)
// 指定時(shí)間間隔
public class func sleep(forTimeInterval ti: TimeInterval)
// 退出線程
public class func exit()
// 線程的優(yōu)先級(jí)處理
// 線程的級(jí)別
public class func threadPriority() -> Double
// 設(shè)置線程級(jí)別
public class func setThreadPriority(_ p: Double) -> Bool
@available(iOS 4.0, *)
// 設(shè)置線程的級(jí)別, 已經(jīng)被棄用,請(qǐ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, *)
// 線程的符號(hào)
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, *)
// 開(kāi)始線程
public func start()
@available(iOS 2.0, *)
// 線程主體方法,這個(gè)方法一般是用來(lái)重寫的
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 的類擴(kuò)展
// 意味著所有的 NSObject 對(duì)象都可以使用下面的方法
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, *)
// 在某個(gè)線程執(zhí)行某方法
public func perform(_ aSelector: Selector, on thr: Thread, with arg: AnyObject?, waitUntilDone wait: Bool, modes array: [String]?)
@available(iOS 2.0, *)
// 在某個(gè)線程執(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?)
}
上面貼頭文件純屬個(gè)人喜好,本人簡(jiǎn)單翻譯為的是后期的被查,解決英文不好的毛病。
1、判斷當(dāng)前線程數(shù)可以知道是否是多線程。
Thread.current() number 為 1 的時(shí)候是主線程,線程數(shù)不為1 就為多線程。數(shù)子沒(méi)有意義。
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)建一個(gè)線程對(duì)象
let thread1 = Thread(target: self, selector: #selector(longOperation), object: "thread1")
// 線程默認(rèn)是不會(huì)啟動(dòng)的
// 必須我們手動(dòng)啟動(dòng)
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)建了一個(gè)線程對(duì)象
// 這樣創(chuàng)建的線程操作性太小
// 我們一般會(huì)使用上面的方法
let thread = Thread()
通過(guò) Thread 直接分離(創(chuàng)建)一個(gè)線程執(zhí)行某個(gè)方法。
使用這種方式創(chuàng)建的線程,線程是直接啟動(dò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)}
一個(gè)方法里面的內(nèi)容只能在一個(gè)線程里面執(zhí)行,block 或閉包除外。
使用 NSObject 的方法直接在后臺(tái)線程執(zhí)行某方法
(實(shí)際上也是創(chuàng)建一個(gè)新的線程對(duì)象,并啟動(dò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 對(duì)象都可以開(kāi)啟子線程。(都具有開(kāi)啟線程的能力)
3、線程屬性
線程名稱
// 線程名稱
public var name: String?
線程的名稱通常在大的商業(yè)應(yīng)用中,希望應(yīng)用程序上架后,捕獲到用戶使用崩潰的一些場(chǎng)景。
如果知道程序在哪個(gè)線程中崩潰,能夠輔助排錯(cuò)。
如果線程非常多,而且在調(diào)試的時(shí)候可以起到輔助作用。
線程堆棧大小
Thread.current().stackSize
// 調(diào)整大小
Thread.current().stackSize = 1024 * 1024
線程的??臻g大小是 統(tǒng)一都是 512 k, 大小是可以修改。
在以前的版本中 主線程是 1024k, 其他線程是 512k ,大小是不能修改。
線程的優(yōu)先級(jí)
// 線程的優(yōu)先級(jí) 0 到1.0 , 1 的優(yōu)先級(jí)最高。
// 默認(rèn)的線程優(yōu)先級(jí)是 0.5
Thread.current().threadPriority
線程的優(yōu)先級(jí)一般不需要修改。線程的優(yōu)先級(jí)不一定決定線程的執(zhí)行循序。
(經(jīng)典例子:優(yōu)先級(jí)反轉(zhuǎn))
優(yōu)先級(jí)高只能說(shuō)明 cpu 在調(diào)度的時(shí)候回優(yōu)先調(diào)度,并不意味著,優(yōu)先級(jí)低的就不會(huì)調(diào)度。
多線程開(kāi)發(fā)注意
- 優(yōu)先級(jí)只能說(shuō)明 cpu 優(yōu)先調(diào)度,并不意味著優(yōu)先級(jí)低的不調(diào)度。(不要改優(yōu)先級(jí))
- 不能相信一次執(zhí)行的結(jié)果。
- 不要去做不同線程的比較。
葵花寶典:
多線程開(kāi)發(fā)一定要簡(jiǎn)單。(越復(fù)雜越不可控)
4、線程間通訊 (重點(diǎn)中的重點(diǎn))
在子線程進(jìn)行耗時(shí)操作,在子線程完成后,根據(jù)子線程的執(zhí)行結(jié)果刷新UI界面。
(有的時(shí)候,不在主線程更新 UI 也不會(huì)有問(wèn)題。 但是一定要在主線程更新 UI)
/**
#selector(refresUI) : 調(diào)用的方法
with: nil 要傳遞到主線程的參數(shù)。我這里傳的是 nil 表示不傳參數(shù)。
waitUntilDone : true 等待主線程方法執(zhí)行完畢
false 不等待主線程方法執(zhí)行完畢
(說(shuō)白了就是線程的串行和并行的問(wèn)題, 為 true 的是線程串行, false 為并行 )
*/
self.performSelector(onMainThread: #selector(refresUI), with: nil, waitUntilDone: true)
第一種創(chuàng)建線程的方式
print("befor -\(Thread.current())")
// 1. thread 對(duì)象, 在子線程中執(zhí)行耗時(shí)操作
let thread = Thread(target: self, selector: #selector(longOperation), object: nil)
// 2. 啟動(dòng)線程
thread.start()
print("after -\(Thread.current())")
// 耗時(shí)操作
func longOperation(sender: AnyObject){
// 模擬的耗時(shí)操作
print("longOperation -\(Thread.current())")
// object 參數(shù)對(duì)象可以用來(lái)進(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}
耗時(shí)操作是在子線程執(zhí)行的,刷新 ui 是在主線程執(zhí)行的
分離線程的方式
進(jìn)行了線程之間的傳值
print("befor -\(Thread.current())")
Thread.detachNewThreadSelector(#selector(longOperation), toTarget: self, with: "detachNewThread")
print("after -\(Thread.current())")
// 耗時(shí)操作
func longOperation(sender: AnyObject){
// 模擬的耗時(shí)操作
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í)行后臺(tái)線程
(我個(gè)人比較喜歡這種方式)
print("befor -\(Thread.current())")
self.performSelector(inBackground: #selector(longOperation), with: "inBackgroundThread")
print("after -\(Thread.current())")
// 耗時(shí)操作
func longOperation(sender: AnyObject){
// 模擬的耗時(shí)操作
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