Swift 實戰-享元模式
設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。GoF提出了23種設計模式,本系列將使用Swift語言來實現這些設計模式
概述
通過共享已存在的對象,減少創建對象內存開銷的設計模式被稱作 享元模式
享元模式 Flyweight 和單例模式 Singleton 像是一對孿生兄弟,二者的表現方式非常相似,但二者的存在目的卻不一樣:
-
單例模式
保證了整個應用聲明周期內,同一個對象只會存在一份內存,并且任何時間都能被訪問使用。 -
享元模式
如果存在可以復用的對象,那么對象將被共享而不是創建新的對象
在iOS開發中,享元模式的最佳實踐就是 UITableView 的復用機制——超出屏幕外的單元格統一被回收放到一個復用隊列之中,等待著需要新的單元格時進行復用。
實戰
筆者最近項目有一個需求,幾乎所有的數據都要保存在本地。由于應用的特殊性,模塊之間需要用到彼此的數據,如果使用單例模式來做,那么同一時間占用的內存是非常的大的,因此以享元模式的思想封裝了一個數據管理類:
class DataManager {
//MARK: - Variable
private static var shareStorage = [String: AnyObject]()
private var storeKey = "DefaultKey"
private var storeData = [AnyObject]()
var data: [AnyObject] {
get {
return storeData
}
}
//MARK: - Operate
funcinsert(data: AnyObject) { }
funcdelete(atindex: Int) { }
funcsave() { }
}
筆者以數據模型的類名作為數據管理的關鍵字,因此創建一個私有的靜態字典用來保存當前正在使用的數據。由于數據以加密的方式存儲在沙盒目錄下,在數據量足夠大的時候,從本地讀取這些數據會占用大量的花銷,因此在數據管理對象被創建的時候需要判斷是否存在可復用的數據,如果不存在再從本地加載:
class DataManager {
init() {
initalizeData()
}
init(storeKey: String) {
self.storeKey = storeKey
initalizeData()
}
private funcinitalizeData() {
if letdata = DataManager.shareStorage[storeKey] {
storeData = dataas! [AnyObject]
} else {
loadData()
DataManager.shareStorage[storeKey] = storeDataas AnyObject?
}
}
private funcloadData() {
// load data from local path
}
}
ok,對于數據的復用已經完成了,剩下的問題是不可能讓字典一直存儲這些數據,否則直接使用單例要更加方便的多。對此,筆者使用了計數功能,保證數據可以在沒有使用的時候進行本地存儲然后釋放:
class DataManager {
deinit {
letcount = DataManager.shareStorage[countKey()] as! Int
if count == 1 {
save()
DataManager.shareStorage[storeKey] = nil
} else {
DataManager.shareStorage[countKey()] = (count - 1) as AnyObject?
}
}
private funcinitalizeData() {
if letdata = DataManager.shareStorage[storeKey] {
letcount = DataManager.shareStorage[countKey()] as! Int
DataManager.shareStorage[countKey()] = (count + 1) as AnyObject?
storeData = dataas! [AnyObject]
} else {
loadData()
DataManager.shareStorage[countKey()] = 1 as AnyObject
DataManager.shareStorage[storeKey] = storeDataas AnyObject?
}
}
private funccountKey() -> String {
return "\(storeKey)Count"
}
}
上面的代碼是初步的邏輯搭建,下一步還需要考慮線程安全等其他問題,這里就不再寫出來了
總結
最開始接觸享元模式概念的時候,筆者是有些混亂的,也不清楚它和單例的區別。簡單來說,這是一種提供了一種擁有單例優點、以及改善了一部分單例缺點的設計模式,但是享元模式更加的復雜,在考慮到多線程的環境下,數據競爭要比單例激烈的多,也危險的多。
來自:http://ios.jobbole.com/89526/