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

时间:2016-09-19 15:29:39

标签: ios swift xcode watchkit swift3

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

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

3 个答案:

答案 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()