Swift 3 中的 dispatch_once 在哪里? [英] Whither dispatch_once in Swift 3?
问题描述
好的,所以我在 Xcode 8 中发现了新的 Swifty Dispatch API.我很高兴使用 DispatchQueue.main.async
,我一直在浏览 Xcode 中的 Dispatch
模块以找到所有新的 API.
Okay, so I found out about the new Swifty Dispatch API in Xcode 8. I'm having fun using DispatchQueue.main.async
, and I've been browsing around the Dispatch
module in Xcode to find all the new APIs.
但我也使用 dispatch_once
来确保诸如单例创建和一次性设置之类的事情不会被执行多次(即使在多线程环境中)...和 dispatch_once
在新的 Dispatch 模块中找不到?
But I also use dispatch_once
to make sure that things like singleton creation and one-time setup don't get executed more than once (even in a multithreaded environment)... and dispatch_once
is nowhere to be found in the new Dispatch module?
static var token: dispatch_once_t = 0
func whatDoYouHear() {
print("All of this has happened before, and all of it will happen again.")
dispatch_once(&token) {
print("Except this part.")
}
}
推荐答案
从 Swift 1.x 开始,Swift 一直在使用 dispatch_once
幕后 执行全局变量和静态属性的线程安全延迟初始化.
Since Swift 1.x, Swift has been using dispatch_once
behind the scenes to perform thread-safe lazy initialization of global variables and static properties.
所以上面的 static var
已经在使用 dispatch_once
,这使得它有点奇怪(并且可能再次使用它作为另一个 dispatch_once 的标记)
.事实上,没有这种递归的使用 dispatch_once
真的没有安全的方法,所以他们摆脱了它.相反,只需使用基于它构建的语言特性:
So the static var
above was already using dispatch_once
, which makes it sort of weird (and possibly problematic to use it again as a token for another dispatch_once
. In fact there's really no safe way to use dispatch_once
without this kind of recursion, so they got rid of it. Instead, just use the language features built on it:
// global constant: SomeClass initializer gets called lazily, only on first use
let foo = SomeClass()
// global var, same thing happens here
// even though the "initializer" is an immediately invoked closure
var bar: SomeClass = {
let b = SomeClass()
b.someProperty = "whatever"
b.doSomeStuff()
return b
}()
// ditto for static properties in classes/structures/enums
class MyClass {
static let singleton = MyClass()
init() {
print("foo")
}
}
所以,如果您一直使用 dispatch_once
进行一次性初始化,从而产生某个值,那就太好了——您可以将该值设为全局变量或您正在初始化的静态属性.
So that's all great if you've been using dispatch_once
for one-time initialization that results in some value -- you can just make that value the global variable or static property you're initializing.
但是如果您使用 dispatch_once
来完成不一定有结果的工作怎么办?您仍然可以使用全局变量或静态属性来做到这一点:只需将该变量的类型设为 Void
:
But what if you're using dispatch_once
to do work that doesn't necessarily have a result? You can still do that with a global variable or static property: just make that variable's type Void
:
let justAOneTimeThing: () = {
print("Not coming back here.")
}()
如果访问全局变量或静态属性来执行一次性工作对您来说并不合适——比如说,您希望您的客户在使用您的库之前调用初始化我"函数——只需将该访问权限包装在一个函数中:
And if accessing a global variable or static property to perform one-time work just doesn't feel right to you -- say, you want your clients to call an "initialize me" function before they work with your library -- just wrap that access in a function:
func doTheOneTimeThing() {
justAOneTimeThing
}
有关更多信息,请参阅迁移指南.
See the migration guide for more.
这篇关于Swift 3 中的 dispatch_once 在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!