2、Thread —— swift3.0

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

你可能感兴趣的:(2、Thread —— swift3.0)