在不使用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
现在翻译的内容。 但除非你有一些理由需要将文件fileprivate
, fileprivate
我可能会将其切换回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()