美文网首页
2、Thread —— swift3.0

2、Thread —— swift3.0

作者: Laughingg | 来源:发表于2016-06-20 20:11 被阅读117次

    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())
    
    打印结果
    <NSThread: 0x7ff791402120>{number = 1, name = main}
    

    objc

    [NSThread currentThread];
    NSLog(@"%@", [NSThread currentThread]);
    
    打印结果:
    2016-06-21 19:28:24.644 Thread-Objc[4072:1165465] <NSThread: 0x7f9e73405100>{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] <NSThread: 0x7f80e2c7a7b0>{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] <NSThread: 0x7f80e2c7a7b0>{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 -<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}
    
    耗时操作是在子线程执行的,刷新 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 -<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 执行后台线程
    (我个人比较喜欢这种方式)

    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 -<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
    
    

    相关文章

      网友评论

          本文标题:2、Thread —— swift3.0

          本文链接:https://www.haomeiwen.com/subject/gpgwdttx.html