1. ホーム
  2. swift

[解決済み] Swiftでdispatch_onceのシングルトンモデルを使う

2022-03-17 12:27:08

質問

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() })

の適切な使用法は何ですか? dispatch_once をSwiftで使用することはできますか?私は最初、このブロックの問題は () というエラーメッセージが表示されますが、調べれば調べるほど、もしかしたら dispatch_once_t を正しく定義してください。

どのように解決するのですか?

tl;dr: この機能を使用するには クラス定数 Swift 1.2 以降を使用していて ネストされた構造体 を使用すると、以前のバージョンをサポートする必要があります。

Swift の経験から、遅延初期化とスレッドセーフをサポートする Singleton パターンを実装するための 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!
    }
}

こちらをご覧ください ギットハブ プロジェクトでユニットテストを行っています。