在不使用dispatch_once_t的情况下转换Swift 3代码

在迁移到Swift 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 } 

在我的class级的顶部,它添加了这个:

 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 

我似乎无法弄清楚如何修复我的代码,有没有人有任何建议?

目前还不清楚您对此代码的期望。 如果有人调用WatchGATracker.setup(tid: "abc")然后调用WatchGATracker.setup(tid: "123")什么? 似乎后者的tid被悄然忽略了。 我不相信这是一个正确的单身人士。

您需要更明确地了解正确的行为。 例如,如果在使用跟踪器之前不调用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 } 

(如注释中所述,如果你想要这个fetch的线程安全,那么你需要添加一个类级别的调度队列来管理它,就像你添加一个实例级的调度队列来处理线程一样 – 该级别的安全。一旦初始化需要参数,您就不会获得自动线程安全。)

当错误显示“使用延迟初始化全局变量”时,它表示如下:

 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() { ... } ... } 

然后你就可以做到

 WatchGATracker.shared.tid = "foo" 

顺便说一句,关于fileprivate ,它表明仅仅是因为这是旧private现在翻译的内容。 但除非你有一些理由需要将文件fileprivatefileprivate我可能会将其切换回private (现在它使其成为词法范围的私有)。

我们都习惯了过于复杂的单例模式……现在实际上非常简单:

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

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

至于setup()函数,我在回答中同意@Rob Napier,但我会更进一步。 如果您正在尝试重新配置单例,那么您做错了。 如果您有一些必需的设置参数因使用情况而异,则应创建单独的实例。

也许你正在尝试重用某种连接或其他function,这会导致你走向单一路径,但如果是这种情况,你应该只将该function提取到它自己的类中,让这些可配置实例共享单例。

 /// 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()