Swift系列三十一 - 多线程

Posted 1024星球

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift系列三十一 - 多线程相关的知识,希望对你有一定的参考价值。

多线程在Swift中也是首先使用GCD。

一、异步

1.1. GCD开启异步线程

示例代码:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        print("主线程", Thread.current)
        
        DispatchQueue.global().async {
            print("子线程", Thread.current)
            DispatchQueue.main.async {
                print("回到主线程", Thread.current)
            }
        }
    }
}
/*
 输出:
 主线程 <NSThread: 0x600000bdc6c0>{number = 1, name = main}
 子线程 <NSThread: 0x600000bb4c80>{number = 6, name = (null)}
 回到主线程 <NSThread: 0x600000bdc6c0>{number = 1, name = main}
 */ 

提示:之前OC中很多类都是NS前缀,但是Swift中和OC对等的类名大部分把NS去掉了。

1.2. GCD任务-DispatchWorkItem

DispatchWorkItem是定义任务的,任务完成后可以通过notify通知其他线程(一般是主线程)做其他任务。

示例代码:

// 定义任务
public typealias Task = () -> Void

public struct Async {
    // 异步线程1:传入子线程任务
    public static func async (_ task: @escaping Task) {
        _async(task)
    }

    // 异步线程2:分别传入子线程和主线程的任务
    public static func async(_ task: @escaping Task, _ mainTask: @escaping Task) {
        _async(task, mainTask)
    }

    public static func _async(_ task: @escaping Task, _ mainTask: Task? = nil) {
        let item = DispatchWorkItem(block: task)
        // 子线程执行任务
        DispatchQueue.global().async(execute: item)
        if let main = mainTask {
            // 子线程执行完毕后通知主线程执行任务
            item.notify(queue: DispatchQueue.main, execute: main)
        }
    }
}

二、延迟

2.1 普通延迟

ios中使用延迟一般使用dispatch_after,但是在Swift中没有这个API,使用的是DispatchQueue.*.asyncAfter

示例代码:

@discardableResult
public static func delay(_ seconds: Double, _ block: @escaping Task) -> DispatchWorkItem {
    let item = DispatchWorkItem(block: block)
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds, execute: item)
    return item
}

2.2. 异步延迟

示例代码(定义函数):

@discardableResult
public static func asyncDelay(_ seconds: Double, _ task: @escaping Task) -> DispatchWorkItem {
    return _asyncDelay(seconds, task)
}

@discardableResult
public static func asyncDelay(_ seconds: Double, _ task: @escaping Task, _ mainTask: @escaping Task) -> DispatchWorkItem {
    return _asyncDelay(seconds, task, mainTask)
}

private static func _asyncDelay(_ seconds: Double, _ task: @escaping Task, _ mainTask: Task? = nil) -> DispatchWorkItem {
    let item = DispatchWorkItem(block: task)
    DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + seconds, execute: item)
    if let main = mainTask {
        item.notify(queue: DispatchQueue.main, execute: main)
    }
    return item
}

示例代码(使用):

class ViewController: UIViewController {
    private var item: DispatchWorkItem?

    override func viewDidLoad() {
        super.viewDidLoad()
           
        item = Async.asyncDelay(3) {
            
        };
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        item?.cancel()
    }
}

为什么定义延迟异步时函数要返回DispatchWorkItem?是因为有可能需要对任务做取消或其他操作。

三、once

dispatch_once在Swift中已被废弃,取而代之的是静态属性(底层还是调用了dispatch_once)。

示例代码:

class ViewController: UIViewController {
    static var onceTask: Void = {
        print("onceTask")
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let _ = Self.onceTask
        let _ = Self.onceTask
        let _ = Self.onceTask
    }
}
// 输出:print("onceTask")

四、加锁

当很多资源同时访问同一块数据的时候,可能会发生抢夺资源的情况,这时候需要一个加锁机制,当上次任务还未结束时,等待到任务完成才能继续下一次任务。

示例代码:

public struct Cache {
    private static var data = [String: Any]()
    private static var lock = DispatchSemaphore(value: 1)
    public static func set(_ key: String, _ value: Any) {
        lock.wait()
        defer {
            lock.signal()
        }
        data[key] = value
    }
}

lock.wait()是加锁,lock.signal()是取消锁(解锁)。加锁的API还有很多:NSLock、NSRecursiveLock等等,使用起来都很简单(只需要注意死锁问题即可)。

以上是关于Swift系列三十一 - 多线程的主要内容,如果未能解决你的问题,请参考以下文章

Qt系列文章之三十一 (基于QThread互斥量的线程同步线程)

MATLAB实战系列(三十一)-基于MATLAB的异步电机调速系统仿真

第三十一节:扫盲并发和并行同步和异步进程和线程阻塞和非阻塞响应和吞吐等

风险模型在时间序列上的改进 ——《系列之三十一》

[系统安全] 三十一.恶意代码检测恶意代码攻击溯源及恶意样本分析

《C#零基础入门之百识百例》(三十一)方法定义 -- 猜数游戏