2016-09-19 54 views
0

在遷移之前斯威夫特3,我有以下代碼:不使用dispatch_once_t的轉換斯威夫特3碼

//Set up singleton object for the tracker 
class func setup(tid: String) -> WatchGATracker { 
    struct Static { 
     static var onceToken: dispatch_once_t = 0 
    } 
    dispatch_once(&Static.onceToken) { 
     _analyticsTracker = WatchGATracker(tid: tid) 
    } 
    return _analyticsTracker 
} 

我收到以下錯誤:

'dispatch_once_t' is unavailable in Swift: Use lazily initialized globals instead 

顯然,轉換工具轉換代碼如下:

class func setup(_ tid: String) -> WatchGATracker { 
    struct Static { 
     static var onceToken: Int = 0 
    } 
    _ = WatchGATracker.__once 
    return _analyticsTracker 
} 

而在我的課堂上,它增加了這個:

private static var __once:() = { 
     _analyticsTracker = WatchGATracker(tid: tid) 
}() 

但我仍然得到一個錯誤:

Instance member 'tid' cannot be used on type 'WatchGATracker' 

TID被聲明爲:

fileprivate var tid: String 

它曾經被聲明爲:

private var tid: String 

我似乎無法弄清楚如何解決我的代碼,有沒有人有任何建議?

+1

您不應該使用這種過時的方法創建單例,請查看[this one]這樣的教程(http://krakendev.io/blog/the-right-way-to-write-一個單身人士)的方式來做到這一點在斯威夫特。 – kabiroberai

+0

那你爲什麼不用'lazy'呢? – holex

+0

@holex - 令人煩惱的是,與'static'和全局變量不同,'lazy'不能確保線程安全,所以你必須實現你自己的同步機制。 – Rob

回答

0

目前還不清楚你希望這個代碼做什麼。如果有人撥打WatchGATracker.setup(tid: "abc"),然後再撥打WatchGATracker.setup(tid: "123"),會發生什麼?後者似乎被悄悄忽略了。我不相信這是一個正確的單身人士。

你需要更清楚地知道正確的行爲是什麼。例如,如果它是一個編程錯誤不使用跟蹤器之前調用setup,你想是這樣的:

class WatchGATracker { 
    static private(set) var instance: WatchGATracker! 

    class func setup(tid: String) { 
     precondition(instance == nil) 
     instance = WatchGATracker(tid: tid) 
    } 

    init(tid: String) { . . . } 
} 

如果程序可以與不同TIDS調用不同的部分,那麼你應該做更多的東西一樣:

static private var instances: [String: WatchGATracker] = [:] 

class func setup(tid: String) -> WatchGATracker { 
    if let instance = instances[tid] { 
     return instance 
    } 

    let instance = WatchGATracker(tid: tid) 
    instances[tid] = instance 
    return instance 
} 

(正如在評論中指出,如果你想線程安全這個取,那麼你就需要添加一個類級別的調度隊列管理它以同樣的方式,你會添加一個實例級調度隊列來處理該級別的線程安全性,一旦初始化需要一個參數,就不會獲得自動線程安全性。)

+0

這些都不是線程安全的... – Rob

+1

已注意。解決這個問題與在實例中解決它相同。 'dispatch_once'不適用於需要構造參數的事物,也不適用於懶惰的全局變量。 –

0

當錯誤說:「使用延遲初始化的全局變量,而不是」,它的提示是這樣的:

class WatchGATracker { 
    private var tid: String 
    static let shared = WatchGATracker(tid: "foo") 
    private init(tid: String) { ... } 
    ... 
} 

或者,如果你真的想給調用者一個機會來設置tid(這是奇怪的圖案對於單),改變init不採取一個參數,使tid含蓄地展開,但不private所有,並宣佈shared,如:

class WatchGATracker { 
    var tid: String! 
    static let shared = WatchGATracker() 
    private init() { ... } 
    ... 
} 

和n您可以做

WatchGATracker.shared.tid = "foo" 

順便說一句,關於fileprivate,它表明,僅僅因爲這是老private現在翻譯成。但除非你有什麼理由需要fileprivate,否則我可能會將它切換回private(現在它使得它對於詞法範圍而言是私有的)。

+0

謝謝你,非常直接的修復,我會嘗試一下。如果應用程序像過去一樣運行,我會接受這個答案。 – iOShepherd

0

我們都習慣了過於複雜的單模式......這是現在其實很簡單:

class WatchGATracker { 
    static let sharedInstance = WatchGATracker() 
    private override init() {} 
} 

來源:http://krakendev.io/blog/the-right-way-to-write-a-singleton

對於setup()功能,我同意@Rob內皮爾在他的回答中,但我會更進一步。如果你想重新配置一個單身人士,你做錯了。如果您有一些必需的設置參數,因用途而異,則應創建單獨的實例。

也許有某種連接或其它功能,你想重用領先你失望的單身路徑,但如果是這樣的話,你應該只提取該功能給它自己的類,並讓這些配置的實例共享單身。

/// Watch Connection singleton 
class WatchConnection: NSObject { 
    static let sharedInstance = WatchConnection() 
    private override init() {} 

    func doSomething() {} 
} 

//Watch tracker class for each instance of a watch 
class WatchGATracker { 
    init(tid: String) { 
     //do something useful 
    } 

    let connection = { WatchConnection.sharedInstance }() 
} 

let one = WatchGATracker(tid: "one") 
one.connection.doSomething()