在写代码的过程当中,我们总会遇到需要保证全局只有一个实例的时候,这个时候就要使用单件模式。
单件模式——它确保了一个类只有一个实例,并提供一个全局访问点。
那么怎么实现单件模式呢?我们来看看最经典的 Java 代码,该怎么实现这个 单件模式。
我们在网上随便搜索“java 单件模式”就能找到不少现成的代码段,这里是其中随机摘抄的一份:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.whut.singleton; public class SingletonObject { private static SingletonObject singleObject; private SingletonObject(){} public static synchronized SingletonObject getInstance() { if(singleObject==null) singleObject=new SingletonObject(); return singleObject; } } |
那么,在 Swift 中该如何使用单件模式呢?
按照“常理”,你可能是这样写的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import Foundation class Singleton { private init() { print("Singleton inited!") } static var singleton:Singleton? class func getSingleton()->Singleton { if let s = singleton { return s } singleton = Singleton() return singleton! } } |
理论上, "Singleton inited!" 只会输出一次,可是真的是这样的吗?
我们来试试看:
1 2 3 4 5 |
import Foundation let a = Singleton.getSingleton() let b = Singleton.getSingleton() let c = Singleton.getSingleton() |
输出结果如下:
1 2 |
Singleton inited! Program ended with exit code: 0 |
这好像没什么问题,那么我们再试试并发:
1 2 3 4 5 6 7 8 9 |
import Foundation let background = NSOperationQueue()//获取一个后台队列 var a:Singleton? for _ in 1...1000 { background.addOperationWithBlock{ a = Singleton.getSingleton() } } |
这里我们就简单地获取后台队列,然后并发地执行1000次获取实例,那么理论上也应该输出一个 "Singleton inited!" 而剩下的999次执行,都是重复的获取同一个实例,那么真的是这样吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Singleton inited! Program ended with exit code: 0 |
显然不是——不过也不是每次都被重新初始化——也就是说,在并发的情况下,这样的写法并不安全,有一定的概率会导致重复的初始化,那么放到实际的环境当中,导致的结果就是在高并发的情况下你的数据被重置、清空了。
Swift 里的单件模式
那么到底该怎样写才能线程线程安全呢?我们把之前的代码改一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import Foundation class Singleton { private init() { print("Singleton inited!") } static let singleton:Singleton? = Singleton() // class func getSingleton()->Singleton { // if let s = singleton { // return s // } // singleton = Singleton() // return singleton! // } } |
这里我们去掉了 getSingleton() 这个 Getter ,转而直接在静态属性里初始化其自身,这里其实是使用了 Swift 自身的 lazy 特性,它会在第一次调用的时候进行初始化,之后就会一直保持引用了。
那么该怎么使用呢?我们改改刚才的测试代码:
1 2 3 4 5 6 7 8 9 |
import Foundation let background = NSOperationQueue()//获取一个后台序列 var a:Singleton? for _ in 1...1000 { background.addOperationWithBlock{ a = Singleton.singleton } } |
高亮的行则是修改的地方,我们同样并发1000,程序执行结果:
1 2 |
Singleton inited! Program ended with exit code: 0 |
终于,执行结果与我们期望的一样了。
本文由 落格博客 原创撰写:落格博客 » Swift 里的 单件模式
转载请保留出处和原文链接:https://www.logcg.com/archives/1734.html