Swift

【Swift/Xcode】swiftのシングルトンについて徹底解説〜初心者でもわかるように解説します。〜

カズキ

今回はSwiftのデザインパターンの1つであるシングルトンについて
初学者にもわかりやすいように解説していきたいと思います。

swiftのシングルトンとは何か

Swiftのシングルトンは、アプリケーショション全体で一度だけインスタンスを生成し、それを共有するデザインパターンです。これにより、アプリケーション内で特定のオブジェクトや機能を一元管理することができます。シングルトンは、特定のオブジェクトを共有するために使用されることが多く、例えば、データベースやネットワーク接続などの共有リソースを管理するために使用されます。

swiftでシングルトンを使用する場面について

Swiftでシングルトンを使用する場面としては、以下のようなものがあります。

  1. アプリケーション全体で共有するリソースの管理: アプリケーション全体で共有するリソース(データベースやネットワーク接続など)を管理するために、シングルトンを使用します。
  2. 設定値の管理: アプリケーション全体で共有する設定値を管理するために、シングルトンを使用します。
  3. 共有データの管理: アプリケーション全体で共有するデータを管理するために、シングルトンを使用します。
  4. ログ管理: アプリケーション全体で共有するログを管理するために、シングルトンを使用します。
  5. システム共通機能の管理: アプリケーション全体で共有するシステム共通機能(例えば、プッシュ通知など)を管理するために、シングルトンを使用します。

これらのように、アプリケーション全体で共有するリソースや機能を管理するために、シングルトンを使用することができます。

swiftのシングルトンはどのように実装するのか

Swiftでシングルトンを実装するには、以下のような手順を踏むことができます。

  1. シングルトンのクラスを定義します。
  2. シングルトンのインスタンスを保持するためのstaticプロパティを定義します。
  3. シングルトンのインスタンスを生成するためのstaticメソッドを定義します。このメソッドは、インスタンスが生成されていなければ新しくインスタンスを生成し、既に生成されていればそのインスタンスを返します。
  4. シングルトンインスタンスにアクセスするためのイニシャライザをprivateに設定します。
  5. シングルトンインスタンスを共有し、シングルトンのインスタンスにアクセスするためのstaticプロパティかstaticメソッドを呼ぶことでシングルトンインスタンスにアクセスすることができます。

例:

class MySingleton {
    static let shared = MySingleton()
    private init() {}
}

これにより、MySingleton.sharedを呼ぶことでMySingletonのインスタンスにアクセスすることができます。

また、このイニシャライザはprivateに設定しているため、他のクラスからは呼ぶことができず、MySingleton.sharedが唯一のインスタンスとしてアクセスできます。

シングルトンの設計パターンについて

Swiftのシングルトンの設計パターンには、以下のようなものがあります。

  1. クラスのインスタンスを生成し、staticプロパティに保存するパターン: シングルトンのクラスを定義し、イニシャライザをprivateに設定し、インスタンスを生成し、staticプロパティに保存します。このようにすることで、アプリケーション全体からアクセスできるインスタンスを生成し、保存することができます。
  2. static let shared = クラス名()を使用するパターン: シングルトンのクラスを定義し、static let shared = クラス名()と記述することで、イニシャライザをprivateに設定し、インスタンスを生成し、staticプロパティに保存することができます。
  3. static let shared = クラス名()を使用し、dispatch_onceを使用するパターン: シングルトンのクラスを定義し、static let shared = クラス名()と記述することで、イニシャライザをprivateに設定し、インスタンスを生成し、staticプロパティに保存することができます。そして、dispatch_onceを使用することで、アプリケーション全体からアクセスできるインスタンスを生成し、保存することができます。

いずれのパターンも、アプリケーション全体で共有するリソースや機能を管理するために、シングルトンを使用することができます。

ただし、マルチスレッド環境下では、dispatch_onceを使用したパターンを選択することが推奨されています。

シングルトンの使用例

Swiftのシングルトンの使用例としては、以下のようなものがあります。

  • 1 ユーザー設定の管理: アプリケーション全体で共有するユーザー設定を管理するために、シングルトンを使用します。
class UserSettings {
    static let shared = UserSettings()
    private init() {}

    var isNotificationEnabled: Bool = true
    var fontSize: Int = 16
}

// 他のクラスからアクセスする
let settings = UserSettings.shared
settings.isNotificationEnabled = false

  • 2 ネットワーク接続の管理: アプリケーション全体で共有するネットーク接続を管理するめに、シングルトンを使用します。
class NetworkManager {
    static let shared = NetworkManager()
    private init() {}

    func fetchData(completion: (Data?) -> Void) {
        // ネットワーク接続を行う
    }
}

// 他のクラスからアクセスする
let network = NetworkManager.shared
network.fetchData { data in
    // データ取得処理
}

  • 3 ログの管理: アプリケーション全体で共有するログを管理するために、シングルトンを使用します。
class LogManager {
    static let shared = LogManager()
    private init() {}

    func logError(_ error: Error) {
        // errorをログに記録する
    }
}

// 他のクラスからアクセスする
let log = LogManager.shared
log.logError(Error.init())

これらのように、アプリケーション全体で共有するリソースや機能を管理するために、シングルトンを使用することができます。

シングルトンと他のデザインパターンの違い

シングルトンデザインパターンは、クラスに対して1つのインスタンスのみが存在することを保証するデザインパターンです。それに対して、他のデザインパターンは、クラスやオブジェクトのインスタンスを使用して、特定のタスクや処理を実行するための方法を定義します。 例えば、状態パターンはオブジェクトの状態に応じて処理を切り替えるために使用されます。また、ストラテジーパターンは、異なるアルゴリズムや手法を実装し、それらを選択して使用するために使用されます。

swiftの状態パターンについて

状態パターンは、オブジェクトの状態に応じて処理を切り替えるためのデザインパターンです。このパターンでは、状態を表すインターフェースやクラスを定義し、それを実装するための複数の状態クラスを作成します。そして、オブジェクトは、その現在の状態に応じて処理を実行します。

例えば、支払いシステムのオブジェクトがある場合、それは「支払い待ち」、「支払い済み」、「キャンセル」などの状態を持つことができます。そして、それぞれの状態に応じて、支払いを処理するための異なる処理を行うことができます。

Swiftでは状態パターンを実装するために、enumを使用する方法が一般的です。

swiftのストラテジーパターンについて

ストラテジーパターンは、異なるアルゴリズムや手法を実装し、それらを選択して使用するためのデザインパターンです。このパターンでは、アルゴリズムを表すインターフェイスやプロトコルを定義し、それを実装するための複数のアルゴリズムクラスを作成します。そして、オブジェクトは、必要に応じて異なるアルゴリズムを選択して使用することができます。

例えば、文字列を比較するアルゴリズムがある場合、それは「辞書順」、「長さ」、「文字数」などの異なるアルゴリズムを持つことができます。そして、それぞれのアルゴリズムに応じて、文字列を比較するための異なる処理を行うことができます。

Swiftではストラテジーパターンを実装するために、protocolを使用する方法が一般的です。

シングルトンの注意点

シングルトンは、アプリケーション全体で1つのインスタンスのみが存在することを保証するためのデザインパターンですが、マルチスレッド環境で使用する際には、競合状態になってしまう可能性があります。

それは、複数のスレッドが同時にシングルトンインスタンスを生成しようとする場合、競合状態になってしまうことがあります。それによって、複数のインスタンスが生成される可能性があり、それはシングルトンの要件を満たしていないことになります。

また、複数のスレッドが同時にシングルトンインスタンスにアクセスしようとする場合、データ競合や不正な結果が発生する可能性があります。

これらの問題を解決するためには、スレッドセーフなコードを書くことが必要です。例えば、「DispatchQueue.once」などのAPIを使用して、インスタンスの生成を同期することで、複数のスレッドが同時にインスタンスを生成しないようにすることができます。また、「synchronized」や「NSLock」などのAPIを使用して、複数のスレッドが同時にインスタンスにアクセスしないようにすることができます。

まとめ

ここまでSwiftのシングルトンについて解説してきました。

皆さんの理解に少しでも役立てたら嬉しいです。

他にもSwiftの記事を書いてるのでよかったら読んでみてください。

また、1人での勉強に限界を感じたらiOSに特化したプログラミングスクール「iOSアカデミア」も検討してみてください!無料相談可能「最短・最速」でiOSエンジニアになれるように手助けしてくれます。