使用场景:只需要一个实例。例如现实世界的资源:服务器;或封装共享资源。
意义:
1、使得创建的实例始终保持一份,避免多次创建。
2、对象与现实资源对应。
3、封装共享资源。
创建Swift单例
1、使用全局常量
//全局变量
let globalLogger = Logger()
//final修饰后,防止子类创建
final class Logger{
private var data = [String]()
private let arrayQ = DispatchQueue.init(label: "arrayQ")
//只在本文件有效,防止其他地方实例
fileprivate init() {
}
func log(msg:String){
//同步添加数组
arrayQ.sync {
data.append(msg)
}
}
func printLog(){
for msg in data {
print("Log:\(msg)")
}
}
}
2、使用结构体
final class BackupServer {
//防止外界初始化
fileprivate init(name:String) {
self.name = name
globalLogger.log(msg: "Created new server \(name)")
}
//BackupServer类型的属性server,初始化值是结构体的静态属性
class var server:BackupServer{
//结构体
struct SingletonWrapper{
//静态属性,用实例赋值
static let singleton = BackupServer.init(name: "MainServer")
}
//返回结构体的属性值
return SingletonWrapper.singleton
}
}
使用注意:
1、Swift的单例模式只适用于引用类型,即类。结构体和其他值类型是不能用的,因为结构体本身具有复制功能。
2、处理并发。因为单例是共享资源,里面如果有数组、字典等集合,在读写操作的时候就需要考虑线程安全问题,避免出现多个线程同时写一个集合。Swift3的GCD需要适应一下。
- 使用串行,如上使用全局变量创建单例中,使用到的
func log(msg:String){
//同步添加数组
arrayQ.sync {
data.append(msg)
}
}
- 也可以串行写,并行读。用到了
barrier
,它的功能就是,barrier block
到达队列顶端时,变成串行队列,所有操作都要等待它完成,完成后恢复并行队列,直到出现下一个barrier block
。
var arrayQ = DispatchQueue.init(label: "arrayQ")
func logItem(item:T) {
//dispatch_barrier 最新写法
//当barrier队列执行的时候,其他线程不能执行,就是串行队列
//执行到其他队列的时候就是并行队列,直到运行到下一个barrier
arrayQ.async(execute: DispatchWorkItem.init(qos: DispatchQoS.default, flags: DispatchWorkItemFlags.barrier, block: {
self.dataItems.append(item.copy() as! T)
self.callback(item)
}))
}
demo
写在后面:
我写的关于设计模式内容,都是来自书《精通Swift设计模式》
,如果有兴趣可以直接买来看看,不用看我的"歪曲理解"。我只是一个搬运工,记录过程,记录一点浅显的理解🙏。