Swift 實戰-享元模式

MolJudkins 8年前發布 | 4K 次閱讀 享元模式 Swift Apple 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/

 

 本文由用戶 MolJudkins 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!