2016-09-22 77 views
1

在這個post,這是非常漂亮,解釋瞭如何單身人士應在斯威夫特來實現,本質上它可以用兩條線來完成:如何實現在Swift中啓動初始化數據的Singleton?

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

但是,會發生什麼,如果我的辛格爾頓應該用一些數據來initalised ?也許它需要封裝一個API密鑰或其他數據,它只能從以外的收到。一個例子可以如下所示:

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

在這種情況下,我們不能初始化私有,因爲我們必須創建一個初始化,需要一個String作爲參數來滿足編譯器:

init(secretKey: String) { 
    self.secretKey = secretKey 
} 

怎樣才能保存,我們仍然確保我們有一個線程安全的單例實例?有沒有一種方法可以避免使用dispatch_once或者我們必須實質上默認回到Objective-C的方式,我們使用dispatch_once來確保初始化器確實只被調用一次?

回答

1

首先,請注意您暗示的ObjC方式不是線程正確的。它可能是「安全的」,因爲它不會崩潰並且不會生成未定義的行爲,但是會默默地忽略具有不同配置的後續初始化。這不是預期的行爲。已知在寫入後發生的讀取器將不會收到寫入的數據。這不符合一致性。所以,擱置這樣一種模式是正確的理論。

那麼什麼是正確的?正確的是這樣的:

import Dispatch 

class TheOneAndOnlyKraken { 
    static let sharedInstanceQueue: DispatchQueue = { 
     let queue = DispatchQueue(label: "kraken") 
     queue.suspend() 
     return queue 
    }() 

    private static var _sharedInstance: TheOneAndOnlyKraken! = nil 
    static var sharedInstance: TheOneAndOnlyKraken { 
     var result: TheOneAndOnlyKraken! 
     sharedInstanceQueue.sync { 
      result = _sharedInstance 
     } 
     return result 
    } 

    // until this is called, all readers will block 
    static func initialize(withSecret secretKey: String) { 
     // It is a programming error to call this twice. If you want to be able to change 
     // it, you'll need another queue at least. 
     precondition(_sharedInstance == nil) 
     _sharedInstance = TheOneAndOnlyKraken(secretKey: secretKey) 
     sharedInstanceQueue.resume() 
    } 

    private var secretKey: String 
    private init(secretKey: String) { 
     self.secretKey = secretKey 
    } 
} 

這需要一個明確的調用TheOneAndOnlyKraken.intialize(withSecret:)。直到有人發出此呼叫,所有sharedInstance的請求都會被阻止。第二次致電initialize將會崩潰。