blog

iPhoneで実装☆デザインパターン 第一回:Singletonパターン

2011.03.26

デバイスソリューション部 モバイルソフトウェアデザイングループの高津です。

iPhone開発を行う中でよく使うデザインパターンを紹介していきたいと思います。
実装コードはObjective-Cとなります。

今回はSingleton(シングルトン)パターンでの実装を紹介します。

▼概要
シングルトンパターンは、あるクラスのインスタンスを生成する際に、
そのインスタンスが1つしか生成されないことを保証することができるデザインパターンです。

よって、毎回インスタンスを生成せずに、どこからでも同じ『シングルトンインスタンス』を共有することができます。

▼使いどころ
データベースやファイルシステムのアクセスオブジェクトを制限したい場合によく利用されるデザインパターンです。
私はCoreDataを使用する際によく利用しています。

また、Cocoaフレームワークの実例として、NSUserDefaultsやNSApplicationがシングルトンで実装されています。

▼実装
シングルトンクラスを作成します。シングルトンインスタンスを取得するため、クラスファクトリメソッドを作成しなければなりません。

staticとして宣言することでインスタンスを共有できます。

これで最初にクラスファクトリメソッドがコールされた時だけ生成を行い、
二回目以降からはシングルトンインスタンスを使いまわすことが可能となります。

基本的には上記の実装を行い、DataAccessCenterのインスタンスを使用したい場合は

として呼び出せばシングルトンインスタンスが返されることになります。

▼改良
このままの実装でもシングルトンパターンとしては成り立っていますが、幾つかの問題が発生します。

・複数のスレッドからアクセスされると複数のインスタンスが生成される可能性がある
・直接allocメッセージが送られた場合に別のインスタンスが生成される
・他、基本プロトコルメソッドのcopyWithZone/release/retain等がコールされることも考慮する

上から順番に解決していきましょう。

▼スレッドの排他制御
クラスファクトリメソッドを複数スレッドから呼び出した場合、複数のインスタンスが生成される危険性があります。

その場合、@synchronizedディレクティブを使用すればスレッドの排他制御が行えます。
@synchronizedでコードを囲むと、ブロックの最後のコードを通過するまで他スレッドはブロックされます。

▼シングルトンインスタンスであることの保証
クラスファクトリメソッドのみでは[[DataAccessCenter alloc] init]メッセージを送られると別のインスタンスが生成され、シングルトンパターンの目的である「インスタンスが1つしか生成されないこと」を保証できません。

そのため、allocWithZone:メソッドをオーバーライドし、別のインスタンスが生成されないようにします。

allocWithZone:メソッドをオーバーライドしたことにより、クラスファクトリメソッドであるsharedCenterも少し修正しました。

▼基本プロトコルメソッドのオーバーライド
上記で直接allocメッセージが送られた場合について対策を行いましたが、copyやreleaseメッセージについても同様のことが言えます。

これらの基本プロトコルメソッドについてもオーバーライドを行って、シングルトンインスタンスの状態が保たれるように実装しなければなりません。

▼まとめ
iPhone開発に関わってからまだ時間は浅いですが、一番よく利用したSingletonパターンの基本を紹介させて頂きました。

「改良」の項目で様々な基本プロトコルメソッドをオーバーライドしていますが、アプリを開発するにあたって「基本はシングルトンインスタンスを使用するが、必要に応じて一時的に別のインスタンスを生成/解放するクラス」を必要とする場面もでてくると思います。
そういった場合は、あえてallocWithZone:や基本プロトコルメソッドをオーバーライドせずに実装する方法もあります。

次回以降もよく使うデザインパターンを順番に紹介させて頂こうと思います。