頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


シングルトンなクラスを継承で作れる?

Objective-Cでシングルトンなクラスをラクに作りたいってお話だよ。

よく聞くよね、シングルトン、singleton。トンってなんだよ、シングルと何が違うのって辞書を見て思わないでもないけど、ともかくこのシングルトンパターンを試してみたんだよ。
今までの俺の理解だとアプリ全体で一つだけしかないオブジェクトをうっかり作り直したりしないようにするためのデザインパターンかなと思っていたんだよ。だったら気を付ければいいじゃないか!ってことでさしてメリットも感じずスルーしてきたんだけどさ、、、ふとかじったところ、これが便利なことに気が付いたよ。やっぱり先人の知恵は敬うべきだね。

Google先生にObjective-Cでシングルトンなクラスの作り方を聞いてみるとよさそうなコードをすぐに教えてくれたよ。
俺はARCは使わない(使えない)ので allocWithZone: や retain をオーバーライドする方法を試してみたんだ。
Objective-C でシングルトンパターン | Sun Limited Mt.
↑ここにコードもあるよ。
これで確かに実現できる。

でも、これだとシングルトンなクラスを作るのに結構な量のコピペが必要になるよね。コードの管理ってことを考えるとコピペするのもあまり好きじゃないし、関連コードを頻繁に目にするのはうっとおしいと思うんだよ、俺は。できればブラックボックス化して目につかないくらいにしたいと思ってさ、こんなことを考えたんだよ。

シングルトンなクラスにするためのNSObjectを継承するサブクラス(名前をSingletonObjectクラスとするよ)を作っておいて、シングルトンなクラス(例えばDataControllerとするよ)を作る場合にこのSingletonObjectクラスを継承すりゃいいんじゃね?って。

SingletonObjectクラスは上のリンクを参考に作っておいて、DataControllerクラス(元々はNSObjectのサブクラス)を次のようにしてSingletonObjectのサブクラスにしておく。
//DataController.h
#import 
#import "SingletonObject.h"

@interface DataController : SingletonObject
これで実際に使ってみると、、、いいじゃない! alloc + init もできない!インポートしてスーパークラスの名前を書き換えるだけでシングルトン用の記述を目にしなくて済むし、コードの管理も俺的にはスッキリする!
こいつはいい!と思ったんだけど、実はすっとぼけた状態でね、、、

同じアプリ内にシングルトンにしたいクラスがもう一つあったとするよ。SoundControllerクラス(NSObjectのサブクラス)としようか。
これも同じ様にSingletonObjectのサブクラスにしようとSingletonObjectクラスを継承させたんだよ。

クラス関係図

すると、、、
DataController *dataController = [DataController sharedInstance];
SoundController *soundController = [SoundController sharedInstance];
この二つのポインタを確認すると同じになるんだよ、、、orz

実行結果

違う、違う、そうじゃない、俺がやりたいのは!そこまで一つにならんでいい!
って嘆いていてもどうしようもない。仕方なく、こんな方法でやってみたんだ。

//static id sharedInstance = nil;//削除
static NSMutableDictionary *dictionary = nil;//追加

+(id)sharedInstance
{
    @synchronized(self) {
        
        if (!dictionary) dictionary = [[NSMutableDictionary alloc] initWithCapacity:0];//追加

        /* 削除
        if (sharedInstance == nil) {
            sharedInstance = [[self alloc] init];
        }
        */
        
        if (![dictionary objectForKey:[[self class] description]]) {//4行追加
            id singletonObject = [[self alloc] init];
            [dictionary setObject:singletonObject forKey:[[self class] description]];
        }
    }
    //return sharedInstance;//削除
    return [dictionary objectForKey:[[self class] description]];//追加
}

+ (id)allocWithZone:(NSZone *)zone 
{
    @synchronized(self) {
        id sharedInstance = [dictionary objectForKey:[[self class] description]];//追加
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;
        }
    }
    return nil;
}
SingletonObjectクラス内でそれを継承しているサブクラスの名前が [[self class] description]] で取得できるのでそれをキーに、作ったオブジェクトをオブジェクトにしてNSDictionaryに入れる、というなんとも奇怪なやり方なんだけどね。
すでにオブジェクトを作ってあれば、dictionaryから呼び出したサブクラスの名前をキーにオブジェクトを返しているんだ。

実行結果

↑これだととりあえず別なオブジェクトになっていて、実現できているようなんだけどさ、、、
これ本当に問題ないのかな???



<< 新しいアルカリイオン整水器を買って10日経過   TopPage  修正版がリリース >>

コメント


管理者にだけ表示を許可する
 

トラックバック

トラックバックURL
http://ringsbell.blog117.fc2.com/tb.php/735-c4f0f076




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad