在迁移到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
}
在我班上最重要的是,它补充了这一点:
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
我似乎无法弄清楚如何修复我的代码,有没有人有任何建议?
答案 0 :(得分:0)
目前还不清楚您对此代码的期望。如果有人拨打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) { . . . }
}
如果程序的不同部分可能使用不同的tid调用,那么您应该执行更类似的操作:
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的线程安全,那么你需要添加一个类级别的调度队列来管理它,就像添加实例级调度队列一样处理该级别的线程安全性。初始化需要参数后,您不会获得自动线程安全。)
答案 1 :(得分:0)
当错误显示"使用延迟初始化的全局变量"时,它建议类似:
class WatchGATracker {
private var tid: String
static let shared = WatchGATracker(tid: "foo")
private init(tid: String) { ... }
...
}
或者,如果您真的想让调用者有机会设置tid
(这是单身人士的奇怪模式),请将init
更改为不参数,使{{1} }隐式解包,但根本不打开tid
,并声明private
如下:
shared
然后你可以做
class WatchGATracker {
var tid: String!
static let shared = WatchGATracker()
private init() { ... }
...
}
顺便说一句,关于WatchGATracker.shared.tid = "foo"
,它只是因为那是旧的fileprivate
现在翻译的内容。但除非你有某种理由需要private
,否则我可能会将其切换回fileprivate
(现在它将其作为词法范围的私有)。
答案 2 :(得分:0)
我们已经习惯了过于复杂的单身人士模式......现在其实非常简单:
class WatchGATracker {
static let sharedInstance = WatchGATracker()
private override init() {}
}
来源:http://krakendev.io/blog/the-right-way-to-write-a-singleton
关于setup()
功能,我在回答中同意@Rob Napier,但我会更进一步。如果您正在尝试重新配置单身,那么您做错了。如果您有一些必需的设置参数因使用情况而异,则应创建单独的实例。
也许你正在尝试重用某种连接或其他功能,这会导致你走向单一路径,但如果是这种情况,你应该只将该功能提取到它自己的类中,让这些可配置实例共享 单身。
/// 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()