在寫代碼的過程當中,我們總會遇到需要保證全局只有一個實例的時候,這個時候就要使用單件模式。
單件模式——它確保了一個類只有一個實例,並提供一個全局訪問點。
那麼怎麼實現單件模式呢?我們來看看最經典的 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! } } |
理論上, "辛格爾頓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次獲取實例,那麼理論上也應該輸出一個 "辛格爾頓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