4.0 gcd swift_swift 4.2 gcd回到主线程 - CSDN
  • Swift 4.0中对 GCD定时器的写法做了很多改进,使之更符合Swift的语言特点,比OC的语法看起来是简明清晰了不少/// GCD定时器倒计时⏳ /// - timeInterval: 循环间隔时间 /// - repeatCount: 重复次数 /// - handler: ...

    Swift 4.0中对 GCD定时器的写法做了很多改进,使之更符合Swift的语言特点,比OC的语法看起来是简明清晰了不少

    /// GCD定时器倒计时⏳
    ///   - timeInterval: 循环间隔时间
    ///   - repeatCount: 重复次数
    ///   - handler: 循环事件, 闭包参数: 1. timer, 2. 剩余执行次数
    public func DispatchTimer(timeInterval: Double, repeatCount:Int, handler:@escaping (DispatchSourceTimer?, Int)->())
    {
        if repeatCount <= 0 {
            return
        }
        let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
        var count = repeatCount
        timer.schedule(wallDeadline: .now(), repeating: timeInterval)
        timer.setEventHandler(handler: {
            count -= 1
            DispatchQueue.main.async {
                handler(timer, count)
            }
            if count == 0 {
                timer.cancel()
            }
        }) 
        timer.resume()
    }
    /// GCD定时器循环操作
    ///   - timeInterval: 循环间隔时间
    ///   - handler: 循环事件
    public func DispatchTimer(timeInterval: Double, handler:@escaping (DispatchSourceTimer?)->())
    {
        let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
        timer.schedule(deadline: .now(), repeating: timeInterval)
        timer.setEventHandler {
            DispatchQueue.main.async {
                handler(timer)
            }
        }
        timer.resume()
    }
    /// GCD延时操作
    ///   - after: 延迟的时间
    ///   - handler: 事件
    public func DispatchAfter(after: Double, handler:@escaping ()->())
    {
        DispatchQueue.main.asyncAfter(deadline: .now() + after) { 
            handler()
        }
    }

    函数的使用

        override func viewDidLoad() {
            super.viewDidLoad()
    
    
            DispatchTimer(timeInterval: 1, repeatCount: 10) { (timer, count) in
                    print("剩余执行次数 = \(count)")
                }
    
            DispatchAfter(after: 5) { 
                print("您好")
            }
        }

    打印结果:
    剩余执行次数 = 9
    剩余执行次数 = 8
    剩余执行次数 = 7
    剩余执行次数 = 6
    剩余执行次数 = 5
    您好
    剩余执行次数 = 4
    剩余执行次数 = 3
    剩余执行次数 = 2
    剩余执行次数 = 1
    剩余执行次数 = 0

    展开全文
  • Swift 4.0 GCD 倒计时按钮

    千次阅读 2018-06-14 11:13:12
    override func viewDidLoad() { super.viewDidLoad() //写一个按钮 btn.frame.size = CGSize(width: 100, height: 50) btn.center = view.center btn.backgroundColor = .red ...
    override func viewDidLoad() {
            super.viewDidLoad()
            //写一个按钮
            btn.frame.size = CGSize(width: 100, height: 50)
            btn.center = view.center
            btn.backgroundColor = .red
            view.addSubview(btn)
            btn.addTarget(self, action: #selector(timeChange), for: .touchUpInside)
            btn.setTitle("发送验证码", for: .normal)
        }

    点击事件:

    @objc func timeChange() {
            
            var time = 10
            let codeTimer = DispatchSource.makeTimerSource(flags: .init(rawValue: 0), queue: DispatchQueue.global())
            codeTimer.schedule(deadline: .now(), repeating: .milliseconds(1000))  //此处方法与Swift 3.0 不同
            codeTimer.setEventHandler {
                
                time = time - 1
                
                DispatchQueue.main.async {
                    self.btn.isEnabled = false
                }
                
                if time < 0 {
                    codeTimer.cancel()
                    DispatchQueue.main.async {
                        self.btn.isEnabled = true
                        self.btn.setTitle("重新发送", for: .normal)
                    }
                    return
                }
                
                DispatchQueue.main.async {
                    self.btn.setTitle("\(time)", for: .normal)
                }
                
            }
            
            codeTimer.activate()
            
        }

    效果图:


    注意:点击事件中的 self.btn.isEnabled  self.btn.setTitle 须放在主线程中进行,不然控制台报错,截图如下:


    展开全文
  • Swift4.0版本中GCD的常用方法还是有比较大的改动,这里做个简单的整理汇总。 GCD的队列 队列是一种遵循先进先出(FIFO)原则的数据结构,是一种特殊的线性表。 主队列 全局队列 串行队列 并行队列 ...

    前言

    在Swift4.0版本中GCD的常用方法还是有比较大的改动,这里做个简单的整理汇总。

    GCD的队列

    队列是一种遵循先进先出(FIFO)原则的数据结构,是一种特殊的线性表。

    主队列 全局队列 串行队列 并行队列
    同步 X 并行同步 串行同步
    异步 串行异步 并行异步 串行异步

    X 表示禁止这么使用,—— 表示不建议这么使用。

    1. 主队列

    主队列默认是串行的,另外主队列不能结合同步函数(sync)使用,会造成线程死锁。

    override func viewDidLoad() {
          super.viewDidLoad()
          // Do any additional setup after loading the view, typically from a nib.
    
          let mainQueue = DispatchQueue.main
          mainQueue.sync {
              print("造成当前线程:\(Thread.current)死锁")
          }
    }

    同时主队列中不应该添加耗时的任务,因为系统的UI相关事务都是在主线程队列中完成的,大量大耗时操作可能会造成卡顿,应该避免。

    主队列最常用的方法是当子线程需要通知主线程做一些UI上面的操作时,结合子线程使用:

    let queue = DispatchQueue(label: "com.roki.thread")
    queue.async {
        // 大量耗时操作
        print("大量耗时操作线程:\(Thread.current)")
        Thread.sleep(forTimeInterval: 2)
    
        DispatchQueue.main.async {
            //回到主线程操作UI
           print("回到主线程:\(Thread.current)")
        }
    }

    DF993F5D-6A1D-4869-A7E8-5E9D871915D8.png

    2. 全局队列

    全局队列是由系统创建的,默认是并行的。全局队列具体运行在哪一个线程,是由系统维护一个线程池,然后挑选其中的一至多条线程来使用。哪条线程会被使用是未知的,是由系统根据当前的并发任务,处理器的负载等情况来决定的。

    • 全局并发同步队列
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        for i in 1...10 {
            DispatchQueue.global().sync {
                //全局并发同步
                Thread.sleep(forTimeInterval: 2)
                print("线程\(Thread.current)正在执行\(i)号任务")
            }
        }
    }

    9C11F7B3-7602-4E3B-94A2-0255DFC77077.png

    从终端输出我们可以知道任务被顺序执行了,这是因为虽然当前是一个并发队列,但是是同步执行的。同步操作会使得在前一个任务完成后才去执行下一个任务。同步与异步的区别还在于它不会创建新的线程,而是直接在当前线程中执行了相关的任务,当前线程是主线程。同步会阻塞当前线程。

    • 全局并发异步队列
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        for i in 1...10 {
            DispatchQueue.global().async {
                //全局并发异步
                Thread.sleep(forTimeInterval: 2)
                print("线程\(Thread.current)正在执行\(i)号任务")
            }
        }
    }

    7D63F60B-3DC4-4071-854E-CCB3E36019E4.png

    从终端输出我们可以知道任务被随机执行了,而且被分配在多个子线程中执行的,这符合并发的本质。另外需要注意的是全局并发异步队列,系统在挑选来执行任务的线程的时候,会挑选除了主线程之外的其他线程。

    3. 自定义队列

    除了上述队列之外,我们还可以使用DispatchQueue创建自定义的队列。
    let queue = DispatchQueue(label: "com.roki.thread")
    需要注意的是上述创建自定义队列的方式,默认创建的是串行队列。
    还有一种创建自定义队列的方法是:

    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)

    iOS10.0 之后上述API更新为:

    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: .workItem, target: nil)

    参数说明:
    1. label 表示队列标签
    2. qos 表示设置队列的优先级
    - .userInteractive 需要用户交互的,优先级最高,和主线程一样
    - .userInitiated 即将需要,用户期望优先级,优先级高比较高
    - .default 默认优先级
    - .utility 需要执行一段时间后,再通知用户,优先级低
    - *.background 后台执行的,优先级比较低
    - *.unspecified 不指定优先级,最低
    3. attributes 表示队列类型,默认为串行队列,设置为.concurrent表示并行队列。iOS 10.0之后 attributes 新增.initiallyInactive属性表示当前队列是不活跃的,它需要调用DispatchQueueactivate方法来执行任务。
    4. autoreleaseFrequency 表示自动释放频率,设置自动释放机制。
    - .inherit 表示不确定,之前默认的行为也是现在的默认值
    - .workItem 表示为每个执行的项目创建和排除自动释放池, 项目完成时清理临时对象
    - .never 表示GCD不为您管理自动释放池

    • 同步串行队列
      其实同步串行队列,没什么意思的,不管是同步操作还是串行操作都会导致任务被一个一个的执行。这个操作尤其是在主线程执行的时候需要注意,避免造成线程的卡顿。
    let queue = DispatchQueue(label: "com.custom.thread")
    queue.sync {
       //同步串行队列
    }
    • 异步串行队列
      因为是串行队列,即使是异步执行的,任务也是按照顺序依次执行的,但是在子线程中执行的。
    let queue = DispatchQueue(label: "com.custom.thread")
    queue.async {
       //异步串行队列
    }

    9D774A76-4F71-49AE-903A-57741B89D1DE.png

    根据iOS10.0 之后attributes新增的.initiallyInactive属性,我们可以创建不活跃队列。
    - 同步串行不活跃队列

    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.initiallyInactive, autoreleaseFrequency: .workItem, target: nil)
    queue.sync {
       //同步串行不活跃队列
    }
    queue.activate()
    • 异步并行不活跃队列
    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: [.initiallyInactive, .concurrent], autoreleaseFrequency: .workItem, target: nil)
    queue.async {
       //异步并行不活跃队列
    }
    queue.activate()
    • 同步并行队列
      只要涉及到同步的,都不会开启新线程,会在当前线程执行任务,同时任务只能依次执行。
    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
    for i in 1...10 {
         queue.sync {
            //并发同步队列
            Thread.sleep(forTimeInterval: 2)
            print("线程\(Thread.current)正在执行\(i)号任务")
         }
    }

    BC7AAE0B-C3FA-4AEB-9593-72E02D4A105F.png

    • 异步并行队列
      异步并行队列就会在多个线程中,随机执行任务。
    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
    for i in 1...10 {
         queue.async {
            //并发异步
            Thread.sleep(forTimeInterval: 2)
            print("线程\(Thread.current)正在执行\(i)号任务")
         }
    }

    EA277C08-A7FF-49B5-B26B-73521A51C5CF.png

    4. 任务组(DispatchGroup)

    如果我们想监听多个任务的执行情况,那么我们需要将任务(异步、同步、串行、并行)都添加到任务组中,然后通过DispatchGroupnotify函数就可以监听是否组内任务都已经完成。

    let group = DispatchGroup()
    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
    for i in 1...10 {
        queue.async(group: group) {
           //并发异步
           Thread.sleep(forTimeInterval: 2)
           print("线程\(Thread.current)正在执行\(i)号任务")
       }
    }
    
    group.notify(queue: DispatchQueue.main) {
         // 通知主线程,子线程操作已完成
         print("所有任务都已经完成")
    }

    05A6287E-81AC-49A0-A277-D53994DB8E0A.png

    5. 任务对象(DispatchWorkItem)

    在Swift4.0 中使用DispatchWorkItem代替原来OC中的dispatch_block_t。 在DispatchQueue执行操作,除了直接传了一个() -> Void 类型的闭包外,还可以传入一个DispatchWorkItem任务对象。DispatchWorkItem的初始化方法可以配置QosDispatchWorkItemFlags,但是这两个参数都有默认参数,所以也可以只传入一个闭包。
    DispatchWorkItemFlags枚举中assignCurrentContext表示QoS根据创建时的context决定。 值得一提的是DispatchWorkItem也有wait方法,使用方式和DispatchGroup一样。调用会等待这个workItem执行完。

    let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
    let workItem = DispatchWorkItem {
         Thread.sleep(forTimeInterval: 2)
         print("线程\(Thread.current)正在执行任务")
    }
    queue.async(execute: workItem)
    
    print("before waiting")
    workItem.wait()
    print("after waiting")

    A25890FA-C5B3-4000-94D1-D00044663A1A.png

    展开全文
  • GCD常用的用法 子线程 DispatchQueue.global().async { print("开一条全局队列异步执行任务") } 主线程 DispatchQueue.main.async { print("在主队列执行任务") } wait var myQueue = ...

    GCD常用的用法

    子线程

    DispatchQueue.global().async {  
             print("开一条全局队列异步执行任务")   
         }  

    主线程

    DispatchQueue.main.async {  
           print("在主队列执行任务")  
     }  
       


    wait

    var myQueue = DispatchQueue(label: "第一条线程")
    var myQueue2 = DispatchQueue(label: "第二条线程")
    let group = DispatchGroup()
    
    myQueue.async(group: group, qos: .default, flags: []) {
        for _ in 0...10 {
    
            print("耗时任务一")
        }
    }
    
    myQueue.async(group: group, qos: .default, flags: []) {
        for _ in 0...10 {
    
            print("耗时任务二")
            sleep(UInt32(3))
        }
    }
    //等待上面任务执行,会阻塞当前线程,超时就执行下面的,上面的继续执行。可以无限等待 .distantFuture
    let result = group.wait(timeout: .now() + 2.0) 
    switch result {
    case .success:
        print("不超时, 上面的两个任务都执行完")
    case .timedOut:
        print("超时了, 上面的任务还没执行完执行这了")
    }
    
    print("接下来的操作")

    notify

    let group = DispatchGroup()  
         myQueue?.async(group: group, qos: .default, flags: [], execute: {   
             for _ in 0...10 {  
      
             print("耗时任务一")  
             }  
         })  
         myQueue?.async(group: group, qos: .default, flags: [], execute: {  
             for _ in 0...10 {  
      
                 print("耗时任务二")  
             }  
         })  
         //执行完上面的两个耗时操作, 回到myQueue队列中执行下一步的任务  
         group.notify(queue: myQueue!) {  
             print("回到该队列中执行")  
         }  

    barrier

    myQueue?.async {//任务一  
                for _ in 0...10 {  
                    print("......")  
                }  
            }  
            myQueue?.async {//任务二  
                for _ in 0...10 {  
                    print("++++++");  
                }  
            }  
      
            // barrier 会等待上面执行完毕再执行下面的,会阻塞当前线程  
            //        myQueue?.async(flags:.barrier ,execute: {//1.  
            //            print("000000")  
            //        })  
      
            myQueue?.async(group: nil, qos: .default, flags: .barrier, execute: {//2.  
                print("000000")  
            })  
      
            myQueue?.async {  
                print("111111")  
            }  


    展开全文
  • Swift4.0 中,GCD的API更加独立,而不再是像OC一样了,所以我们经常遇到这样一种场景,某个页面需要多个网络请求才可以获得全部数据,在没有顺序要求的情况下,使用GCD Group进行线程调度是最合适的,如果存在顺序...
  • GCD 定时器

    2015-07-12 19:00:38
    #import "GCD.h" 二、增加gcdTimer、normalTimer变量 @property (nonatomic,strong)GCDTimer *gcdTimer; @property (nonatomic,strong)NSTimer *normalTimer; 实现下面两个方法: - (void)...
  • swiftGCD

    2017-08-24 16:37:35
    http://www.jianshu.com/p/737233208d40 作者的讲解列子比较好
  • 升级由swift2.3->swift4.0

    千次阅读 2017-10-12 19:24:19
    本次升级由swift2.3->swift4.0 swift2.3升级swift3.0 pravite -> fileprivate Publice -> open 枚举更换小写 方法名更精简,后面括号移除 gcd方法改变 gcdtimer创建方法返回值类型变了 DispatchSource ->...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • swift3.0 GCD

    千次阅读 2016-09-28 11:17:42
    var myQueue: DispatchQueue? var myQueueTimer: DispatchQueue? var myTimer: DispatchSourceTimer? var myGroup: DispatchGroup? var mySource: DispatchSource?//MARK: - 并行队列 没有attributes,默认是
  • 1,程序的挂起和退出 由于iOS设备资源有限。...那么原先那个程序便进入后台被挂起,不是退出,只是停止执行代码,同时它的内存被锁定。当应用程序恢复时,它会从停止的位置重新开始。 ...2,如下特殊的应用程序可以在...
  • GCD-信号量(dispatch_semaphore_t)

    千次阅读 2016-08-29 00:18:17
    信号量在多线程开发中被广泛使用,当一个线程在进入一段关键代码之前,线程必须获取一个信号量,一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待前面的线程释放信号量。...
  • Swift2.3 --> Swift3.0 的变化

    千次阅读 2016-10-15 09:45:08
    用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Syntax… 让Xcode帮我们把Swift2.3的代码转换为Swift3.0。 手动调出Xcode自动转换Swift2.3 到 Swift3.0弹出语言版本选择界面,选择Covert ...
  • swift3.0 中如何在主线程中刷新UI

    万次阅读 2016-07-31 12:18:25
    类似OC 中的GCD,只是调用方法不同,更方便,如下代码,功能为刷新tableview;   DispatchQueue.main.async(execute: {  self.listTableview.reloadData() })
  • swift中没有了#Define这种宏定义了,可以用let来声明常量来取代,判断当前系统版本对于复杂表达式的宏,可以用全局的func函数代替
  • //// ViewController.swift// 004-GCD//// Created by 庄壮勇 on 2018/1/8.// Copyright © 2018年 Personal. All rights reserved.//import UIKitclass ViewController: UIViewController { override func ...
  • swift3.0 延迟执行

    千次阅读 2016-12-27 17:23:18
    //延时1s执行 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1*NSEC_PER_SEC))/Double(NSEC_PER_SEC)){ //code }
  • Swift 3.0多线程

    千次阅读 2016-10-26 11:32:00
    本文只介绍Grand Central Dispath(GCD) 个人认为一个GCD就够用了,可能是改版或是其他的在找之前写的多线程方法时发现不能用了,看文档之后发现改了,现在看上去更加简单易用。 DispatchQueue.global().async { ...
1 2 3 4 5 ... 19
收藏数 372
精华内容 148
关键字:

4.0 gcd swift