私は Swift で使用するための適切なシングルトン モデルを考案しようとしています。これまでのところ、次のように動作する非スレッド セーフ モデルを実現できました。
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
}
if !Static.instance {
Static.instance = TPScopeManager()
}
return Static.instance!
}
}
シングルトン インスタンスを Static 構造体にラップすると、複雑な命名スキームなしでシングルトン インスタンスと衝突しない単一のインスタンスが可能になり、かなりプライベートになります。ただし、明らかにこのモデルはスレッドセーフではありません。そこで、dispatch_once
全体に次のものを追加してみました。
class var sharedInstance: TPScopeManager {
get {
struct Static {
static var instance: TPScopeManager? = nil
static var token: dispatch_once_t = 0
}
dispatch_once(Static.token) { Static.instance = TPScopeManager() }
return Static.instance!
}
}
しかし、次の行でコンパイラ エラーが発生しますdispatch_once
。
式の型 'Void' を型 '()' に変換できません
構文のさまざまなバリエーションを試してみましたが、すべて同じ結果になるようです。
dispatch_once(Static.token, { Static.instance = TPScopeManager() })
Swiftの正しい使い方は何ですかdispatch_once
? 最初はエラー メッセージの のため、ブロックに問題があると考えました()
が、調べれば調べるほど、 をdispatch_once_t
正しく定義することが問題なのではないかと考えるようになりました。
ベストアンサー1
tl;dr: Swift 1.2 以降を使用している場合はクラス定数アプローチを使用し、以前のバージョンをサポートする必要がある場合はネストされた構造体アプローチを使用します。
私の Swift の経験から、遅延初期化とスレッド セーフティをサポートするシングルトン パターンを実装する方法は 3 つあります。
クラス定数
class Singleton {
static let sharedInstance = Singleton()
}
このアプローチは、Swiftがクラス定数(および変数)を遅延初期化し、の定義によりスレッドセーフであるため、遅延初期化をサポートしますlet
。これは現在公式に推奨される方法シングルトンをインスタンス化します。
クラス定数は Swift 1.2 で導入されました。以前のバージョンの Swift をサポートする必要がある場合は、以下のネストされた構造体アプローチまたはグローバル定数を使用します。
ネストされた構造体
class Singleton {
class var sharedInstance: Singleton {
struct Static {
static let instance: Singleton = Singleton()
}
return Static.instance
}
}
ここでは、ネストされた構造体の静的定数をクラス定数として使用しています。これは、Swift 1.1 以前に静的クラス定数がなかったことに対する回避策であり、関数内の静的定数と変数がなかったことに対する回避策としても機能します。
一度だけディスパッチ
従来の Objective-C アプローチを Swift に移植しました。ネストされた構造体アプローチに比べて利点がないことはほぼ確実ですが、構文の違いが興味深いので、とにかくここに記載します。
class Singleton {
class var sharedInstance: Singleton {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: Singleton? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = Singleton()
}
return Static.instance!
}
}
これを見てGitHubユニットテスト用のプロジェクト。