2010-03-27

SharedCenterというクラスを書いてみた

Cocoaでユーティリティ的に使うクラスの定番パターンで、singletonパターンがあります。NSNotificationCenterがいい例で、アプリケーションワイドで使う機能をクラスにする場合に便利なパターン。こんな感じ。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sayHello:) name:HelloWorldNotification object:nil];

これに従って、自前で作るシングルトンクラスもなんちゃらセンターと言う名前で作りがちです。僕の場合、


  • SupportCenter
  • ActivityCenter
  • DownloadCenter

などなど。それぞれのクラスにクラスメソッドとしてsharedCenterというメソッドを定義して使ってます。こんな感じ。

[[SupportCenter sharedCenter] alertError:error];

このパターン、便利なんですがコードの中では結局グローバル変数を使って管理するという、まああまり見たくないコードでして、アナライザーに文句言われないためにもちゃんと終了時にグローバル変数を破棄してあげる必要があったり。簡単なことだけどちょっと面倒くさい。

というわけで、メタに考えました。シングルトンを管理するシングルトンクラス、SharedCenter。

SharedCenter.h
//
//  SharedCenter.h
//  Ramblin
//
//  Created by Yosuke Suzuki on 10/03/27.
//  Copyright 2010 Kanshin, Inc.. All rights reserved.
//

#import <foundation/foundation.h>


@interface SharedCenter : NSObject

+ (id)center:(Class)cls;
+ (void)registerCenter:(id)center forClass:(Class)cls;

@end

SharedCenter.m
//
//  SharedCenter.m
//  Ramblin
//
//  Created by Yosuke Suzuki on 10/03/27.
//  Copyright 2010 Kanshin, Inc.. All rights reserved.
//

#import "SharedCenter.h"


@implementation SharedCenter

static NSMutableDictionary *sharedCenters = nil;

+ (void)initialize {
  sharedCenters = [[NSMutableDictionary alloc] init];
  
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeCenters:) name:UIApplicationWillTerminateNotification object:nil];
}

+ (id)center:(Class)cls {
  id center = nil;
  
  @synchronized(sharedCenters) {
    NSString *className = NSStringFromClass(cls);
    center = [sharedCenters objectForKey:className];
    if (!center) {
      center = [[cls alloc] init];
      [sharedCenters setObject:center forKey:className];
      [center release];
    }
  }
  
  return center;
}

+ (void)registerCenter:(id)center forClass:(Class)cls {
  @synchronized(sharedCenters) {
    [sharedCenters setObject:center forKey:NSStringFromClass(cls)];
  }
}

+ (void)closeCenters:(NSNotification *)notification {
  [sharedCenters release];
  sharedCenters = nil;
  
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

このクラスを使えば、どんなクラスでも簡単にシングルトンパターンが使えます。しかもグローバル変数は一つだけ。すっきりです。

SupportCenter.h
@interface SupportCenter : NSObject {
...
}

+ (SupportCenter *)sharedCenter; // 定義を追加
...

SupportCenter.m
#import "SupportCenter.m.h"
#import "SharedCenter.h"

@implementation ActivityCenter

// 実装を追加
+ (ActivityCenter *)sharedCenter {
return [SharedCenter center:[self class]];
}

...

2010-03-05

Cacoo便利なんだけどMac版のFlashの日本語入力がインライン入力できなくていらいらするので書き捨て入力欄を作るブックマークレットを作ってみた件

これをブックマーク登録→ Add Cacoo ScrachPad

はるかに便利。