2017-04-13 102 views
5

我有一個類像這樣:如何使Swift類Singleton實例線程安全?

class Database { 
    static let instance:Database = Database() 
    private var db: Connection? 

    private init(){ 
     do { 
     db = try Connection("\(path)/SalesPresenterDatabase.sqlite3") 
     }catch{print(error)} 
    } 
} 

現在我使用Database.instance.xxxxxx執行類中的函數訪問這個類。但是,當我從另一個線程訪問實例時,它會拋出奇怪的結果,就好像它試圖創建另一個實例一樣。我應該在同一個線程中引用實例嗎?

爲了澄清奇怪的結果表明,數據庫I /因爲兩個實例的O錯誤試圖同時訪問數據庫

更新
請參閱在數據庫代碼更多信息這個問題:Using transactions to insert is throwing errors Sqlite.swift

+6

Swift創建單線程是線程安全的。這並不意味着你在單例實例中調用的函數將神奇般地線程安全。如果你需要使函數線程安全,你需要使用類似信號量,串行調度隊列或操作隊列的東西 – Paulw11

+0

'但是,當我從另一個線程訪問實例時,它會拋出奇怪的結果,就好像它試圖創建另一個實例一樣不這麼認爲,考慮到'Database'類的當前定義,你**不能**創建2個實例。然而,也許有更多的代碼進入你沒有展示的那個類。 順便說一句:對你的課最後一個改進:你應該聲明它爲'final'來防止子類化。 –

+0

該類中的其他代碼顯示** addRow **函數。這個函數在alamofire完成塊中被調用,然後在不能插入數據的地方拋出錯誤。有趣的是,如果我刪除了所有對我的Database.instance的調用。單身,並讓有問題的代碼首先運行它,它會正常工作... –

回答

5
class var shareInstance: ClassName { 

    get { 
     struct Static { 
      static var instance: ClassName? = nil 
      static var token: dispatch_once_t = 0 
     } 
     dispatch_once(&Static.token, { 
      Static.instance = ClassName() 
     }) 
     return Static.instance! 
    } 
} 

USE:讓對象:類名= ClassName.shareInstance

夫特3.0

class ClassName { 
    static let sharedInstance: ClassName = { ClassName()}() 
} 

USE:讓對象:類名= ClassName.shareInstance

+0

我正在使用swift3,因此dispatch_once_t選項對我來說不可用.... –

1

在夫特3.0添加一個私有初始化,以防止他人使用默認()初始化。

class ClassName { 
    static let sharedInstance = ClassName() 
    private init() {} //This prevents others from using the default '()' initializer for this class. 
}