Swift的多线程开发和OC基本一样,区别仅仅在于方法不一样。iOS的多线程原理可以直接看之前的OC博客OC多线程之认识和使用,这里不做详细解读,仅针对Swift的写法进行说明
主要内容:
- 实现多线程
- 常见API
- 加锁
1. 实现多线程
代码实现:
/*
1、多线程
*/
public static func async(_ task: @escaping Task) {
_async(task)
}
public static func async(_ task: @escaping Task,
_ mainTask: @escaping Task) {
_async(task, mainTask)
}
private 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)
}
}
说明:
- 任务本身也是用一个函数实现
- 这里先定义一个_async函数用来异步处理任务
- 传入异步任务和主线任务
- 主线任务非必须,默认为nil
- 任务创建:
- 通过DispatchWorkItem函数将函数包装成任务
- 调度任务执行:
- 通过DispatchQueue.global()得到全局并发队列
- 调用async开始异步执行任务
- 回到主线程执行:
- let main = mainTask是值绑定模式,拿到的main是解包后的
- 直接通过子线程任务调用notify进行唤醒操作,此时传入线程和主线任务
2. 常见API
在CO中有多种,这里仅写两种,后续会继续补充
2.1 延迟执行
同步延迟:
@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
}
说明:
- 通过函数asyncAfter函数进行延迟操作
- 这里是主线程调用的,因此是同步的,会阻塞主线程
异步延迟:
@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
}
说明:
- 全局队列调用asyncAfter就是异步延迟
- 执行后再回到主线程中
2.2 单例
在Swift中没有专门的单例,只能通过类型属性或者全局变量\常量(这个C语言本身也是这样的,不是Swift特有的)
代码:
fileprivate let initTask2: Void = {
print("initTask2---------")
}()
class ViewController: UIViewController {
static let initTask1: Void = {
print("initTask1---------")
}()
override func viewDidLoad() {
super.viewDidLoad()
let _ = Self.initTask1
let _ = initTask2
}
}
说明:
- 这里的initTask2是全局变量,所以是单例的
- 默认自带 lazy + dispatch_once
- 通过查看汇编可以看到底层就是通过dispatch_once来实现的
3. 加锁
Swift的加锁和OC基本一样,只是写法不一样而已,这里列举几种。详细锁的认识可以看博客11 - OC多线程之锁的认识
Lock锁:
public struct Cache {
private static var data = [String: Any]()
private static var lock = NSLock()
public static func get(_ key: String) -> Any? {
data[key]
}
public static func set(_ key: String, _ value: Any) {
lock.lock()
defer { lock.unlock() }
data[key] = value
}
}
NSRecursiveLock锁:
public struct Cache {
private static var data = [String: Any]()
private static var lock = NSRecursiveLock()
public static func get(_ key: String) -> Any? {
data[key]
}
public static func set(_ key: String, _ value: Any) {
lock.lock()
defer { lock.unlock() }
data[key] = value
}
}
信号量:
public struct Cache {
private static var data = [String: Any]()
private static var lock = DispatchSemaphore(value: 1)
private static var lock = NSRecursiveLock()
public static func get(_ key: String) -> Any? {
data[key]
}
public static func set(_ key: String, _ value: Any) {
lock.wait()
defer { lock.signal() }
data[key] = value
}
}
说明:
- 通过DispatchSemaphore来创建信号量
- 信号量可以加锁也可以设置并发数