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 {
// 获取当前执行的线程
// 通过当前线程的 number 属性, number == 1 的时候为单线程, number > 1 的时候是多线程, number 的数字没有很多的参考价值
public class func current() -> Thread
// 分离出新线程, 类方法, (直接创建一个线程对象,并开启线程)
// 当我们给需要在新线程中执行某方法的时候可以用这个方法
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()
// 线程的优先级处理
// 线程的级别
public class func threadPriority() -> Double
// 设置线程级别
public class func setThreadPriority(_ p: Double) -> Bool
@available(iOS 4.0, *)
// 设置线程的级别, 已经被弃用,请用下面的服务质量
public var threadPriority: Double // To be deprecated; use qualityOfService below
@available(iOS 8.0, *)
// 服务质量
public var qualityOfService: QualityOfService // read-only after the thread is started
@available(iOS 2.0, *)
// 调用堆栈返回的地址
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, *)
// 获取栈内存大小 , 默认 512k
public var stackSize: Int
@available(iOS 2.0, *)
// 判断是否是主线程
public var isMainThread: Bool { get }
@available(iOS 2.0, *)
// 判断当前线程是否是主线程
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?)
// 线程状态的判断
@available(iOS 2.0, *)
// 线程是否执行
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
// 已经变成单线程
public static let NSDidBecomeSingleThreaded: NSNotification.Name
// 线程将要推出
public static let NSThreadWillExit: NSNotification.Name
}
// NSObject 的类扩展
// 意味着所有的 NSObject 对象都可以使用下面的方法
extension NSObject {
// 在主线程执行某方法
public func performSelector(onMainThread aSelector: Selector, with arg: AnyObject?, waitUntilDone wait: Bool, modes array: [String]?)
// 在主线程执行某方法
public func performSelector(onMainThread aSelector: Selector, with arg: AnyObject?, waitUntilDone wait: Bool)
@available(iOS 2.0, *)
// 在某个线程执行某方法
public func perform(_ aSelector: Selector, on thr: Thread, with arg: AnyObject?, waitUntilDone wait: Bool, modes array: [String]?)
@available(iOS 2.0, *)
// 在某个线程执行某方法
public func perform(_ aSelector: Selector, on thr: Thread, with arg: AnyObject?, waitUntilDone wait: Bool)
@available(iOS 2.0, *)
// 在后头执行选中的方法
public func performSelector(inBackground aSelector: Selector, with arg: AnyObject?)
}
上面贴头文件纯属个人喜好,本人简单翻译为的是后期的被查,解决英文不好的毛病。
1、判断当前线程数可以知道是否是多线程。
Thread.current()
number 为 1 的时候是主线程,线程数不为1 就为多线程。数子没有意义。
print(Thread.current())
打印结果
{number = 1, name = main}
objc
[NSThread currentThread];
NSLog(@"%@", [NSThread currentThread]);
打印结果:
2016-06-21 19:28:24.644 Thread-Objc[4072:1165465] {number = 1, name = main}
使用函数判断是否是多线程
if Thread.isMultiThreaded() {
print("是单线程执行")
}
objc
if (![NSThread isMultiThreaded]) {
NSLog(@"中是单线程!");
}
2、线程的创建
// 创建一个线程对象
let thread1 = Thread(target: self, selector: #selector(longOperation), object: "thread1")
// 线程默认是不会启动的
// 必须我们手动启动
thread1.start()
// 线程执行的的方法
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]);
}
// 这样就创建了一个线程对象
// 这样创建的线程操作性太小
// 我们一般会使用上面的方法
let thread = Thread()
通过 Thread 直接分离(创建)一个线程执行某个方法。
使用这种方式创建的线程,线程是直接启动的
Thread.detachNewThreadSelector(#selector(longOperation), toTarget: self, with: "newThread")
// 线程执行的方法
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]);
}
打印结果
2016-06-21 19:46:56.170 Thread-Objc[4351:1183028] newThread
2016-06-21 19:46:56.171 Thread-Objc[4351:1183028] {number = 2, name = (null)}
一个方法里面的内容只能在一个线程里面执行,block 或闭包除外。
使用 NSObject 的方法直接在后台线程执行某方法
(实际上也是创建一个新的线程对象,并启动线程)
self.performSelector(inBackground: #selector(longOperation), with: "newThread")
// 线程执行的方法
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]);
}
打印结果
2016-06-21 19:46:56.170 Thread-Objc[4351:1183028] newThread
2016-06-21 19:46:56.171 Thread-Objc[4351:1183028] {number = 2, name = (null)}
这种方式表明:
任何 NSObject 对象都可以开启子线程。(都具有开启线程的能力)
3、线程属性
线程名称
// 线程名称
public var name: String?
线程的名称通常在大的商业应用中,希望应用程序上架后,捕获到用户使用崩溃的一些场景。
如果知道程序在哪个线程中崩溃,能够辅助排错。
如果线程非常多,而且在调试的时候可以起到辅助作用。
线程堆栈大小
Thread.current().stackSize
// 调整大小
Thread.current().stackSize = 1024 * 1024
线程的栈空间大小是 统一都是 512 k, 大小是可以修改。
在以前的版本中 主线程是 1024k, 其他线程是 512k ,大小是不能修改。
线程的优先级
// 线程的优先级 0 到1.0 , 1 的优先级最高。
// 默认的线程优先级是 0.5
Thread.current().threadPriority
线程的优先级一般不需要修改。线程的优先级不一定决定线程的执行循序。
(经典例子:优先级反转)
优先级高只能说明 cpu 在调度的时候回优先调度,并不意味着,优先级低的就不会调度。
多线程开发注意
- 优先级只能说明 cpu 优先调度,并不意味着优先级低的不调度。(不要改优先级)
- 不能相信一次执行的结果。
- 不要去做不同线程的比较。
葵花宝典:
多线程开发一定要简单。(越复杂越不可控)
4、线程间通讯 (重点中的重点)
在子线程进行耗时操作,在子线程完成后,根据子线程的执行结果刷新UI界面。
(有的时候,不在主线程更新 UI 也不会有问题。 但是一定要在主线程更新 UI)
/**
#selector(refresUI) : 调用的方法
with: nil 要传递到主线程的参数。我这里传的是 nil 表示不传参数。
waitUntilDone : true 等待主线程方法执行完毕
false 不等待主线程方法执行完毕
(说白了就是线程的串行和并行的问题, 为 true 的是线程串行, false 为并行 )
*/
self.performSelector(onMainThread: #selector(refresUI), with: nil, waitUntilDone: true)
第一种创建线程的方式
print("befor -\(Thread.current())")
// 1. thread 对象, 在子线程中执行耗时操作
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 参数对象可以用来进行线程之间传值
self.performSelector(onMainThread: #selector(refresUI), with: nil, waitUntilDone: false)
}
// 刷新界面
func refresUI(){
print("refresUI -\(Thread.current())")
}
// 打印结果
befor -{number = 1, name = main}
after -{number = 1, name = main}
longOperation -{number = 3, name = (null)}
refresUI -{number = 1, name = main}
耗时操作是在子线程执行的,刷新 ui 是在主线程执行的
分离线程的方式
进行了线程之间的传值
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)")
}
// 打印的结果
befor -{number = 1, name = main}
after -{number = 1, name = main}
longOperation -{number = 3, name = (null)} + 线程之间的传递的值:detachNewThread
refresUI -{number = 1, name = main} + 线程之间的传递的值:detachNewThread
用 NSObject 执行后台线程
(我个人比较喜欢这种方式)
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)")
}
打印结果
befor -{number = 1, name = main}
after -{number = 1, name = main}
longOperation -{number = 3, name = (null)} + 线程之间的传递的值:inBackgroundThread
refresUI -{number = 1, name = main} + 线程之间的传递的值:inBackgroundThread