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

はるかに便利。

2010-02-03

gitのリモートのブランチを削除する方法

$ git push origin :ブランチ名

コロンの意味がわかんないけど、とりあえず忘れないように。

Diplomacy on iPadを作る計画。

2010年、今年の個人的な目標、iPad用のアプリとしてディプロマシーを作る。iPadでやると、マップの操作性も戦術練るにもいろいろ出来そうだし、秘密交渉の演出も素敵にできそう。秘密文書が届くとか。チャットとか。あーカメラがついていれば。

Diplomacy MOE
Web上で遊べるディプロマシー。これがお手本になるはず。参考にさせてもらいます。

AppStoreのバージョン番号ではまる


ランブリンのバージョンアップ版をリリースしようと昨夜から奮闘した記録。

最初のバージョンが1.0でだして、次のマイナーアップデート版を1.01でだしました。ここまでは問題なかったのですが、昨日出すものが機能的にも増えたこともあり、1.02ではなく1.1にしましょうと決定しました。

で、いざリリースの段階になって、サブミットしてみると

The binary you uploaded was invalid. The key CFBundleVersion in the Info.plist file must contain a higher version than that of the previously uploaded version.
 これは困った。でGoogle様に聞いてみたところ、iPhone Dev SDKに記述を見つけました


Registered Member

Join Date: Jul 2009
Posts: 8
Just went through this process with fairly simple version numbers and here's what I found;

Original version '1.0'.

Next upgrade version '1.01' - worked fine.

Tried to submit an upgrade to version '1.1' and got the "CFBundleVersion in the Info.plist file must contain a higher version than that of the previously uploaded version" error.

After much messing around with the package including check the version in the package contents of the built program submitted as version '1.10' and it worked.

Seems like there is a problem with the string to float conversion that Apple is doing.


なるほど、1.01 の次は 1.10ならオッケーなのか。ではそれで...って1.10ってなんだよ!「十」ってなんだ。マイナーバージョン10はないだろう。SuperClock 3.9.10 ぐらいしか聞いたことないぞ。これはそのまま採用しづらいな。


じゃあ、1.1.0 ならどうだ。これならまだ意味は通じるので再度チャレンジ。さて...失敗。


orz




やっぱり1.10しかないか。とバイナリーは作り直して、ふと思う。表記上はあくまで1.1.0としたいのでiTunes Connectでの表記と変えてみてはどうなるか。前に一致してないからダメだよ、といわれたんだけど物は試し。エイヤっとアップしたら、なんと問題なく通った!おぉ、じゃあAppStoreにでるバージョン表記とBundleVersionは関係ないのか?関係がないならいっそ違う番号体系になっているほうが間違いは少ない。ということで、最終的には


iTunesConnect Version = 1.1.0
Info.plist CF Bundle Version = 2


という状態でアップしました。問題はなし。


混乱を極めたバージョン問題ですが、結局見た目のバージョンと内部バージョンを分けるというのがベスト。AppStoreにバイナリーをサブミットしたときに言われエラーは、結局内部バージョンを上げなさいということ。そのバージョンと表記上のバージョン(テキストフィールドにいれるもの=ユーザーの目に触れるもの)は別と考えたほうが混乱はない。だいたい戦略上の理由で見た目のバージョンは決められることも多いし。


ただし、アプリ内のバージョン表記も必要で、これは今までCFBundleVersionKeyを参照していたので、新たにDisplayBundleVersion という項目を追加しました。今後箱の二本立てで管理することにします。

2010-01-29

iPadにはプラグインの仕組みが欲しいな

iPhoneにはプラグインは必要ないかと思ってた。画面も小さいしアプリの規模もそんな大きくない。解決したい物事に特化した単機能の小さいアプリがたくさんそろっていればいいかなぁと。

でも、iPadは事情が違う。移動中に使うというよりは、リビングとかデスクとかカフェとか、落ち着いた場所でじっくり使うモノになりそう。画面もでかいしアプリが出来ることもどんどん高度になっていく。裏を返すと、その分アプリを作るのが大変になる。

例えば、とてもじゃないけど、Pagesに対抗するワープロアプリを書こうなんて考えもしない。書けたとしたら$10じゃ売れない。とても無理。

そしたら、iPadにもiPhoneのアプリみたいに、シンプルなソリューションを提供する場所が必要だと思う。もちろんこれまで通りアプリ作ればいいってことも多いとは思うけど。組み合わせたい機能というのはたくさんある。

例えば?

  • テキストの編集中に表示されるメニューに翻訳機能を提供したい
  • 写真ライブラリの共有メニューに、うちのサービスへのアップロード機能もつけたい
  • Pagesの書類を別の形式で書き出したい
...あんまりないか(笑)。まあ、次の主戦場はアプリではなくもっと機能に集中させて欲しいなぁ、というのが開発者の希望なのかな。AppStore、アプリ内課金、ときたので、機能別課金、PluginStoreみたいなことをやってほしい。

ちなみに、プラグイン機能をつけるとセキュリティ的にやばい、というのは、アプリがみんな好き勝手に自分の独自実装で機能を拡張しようとした場合で、システムがプラグインを管理し、データ中心名設計をすれば問題なく仕組みは作れると思います。どうせStore経由でしか取得できないんだろうし。


2010-01-25

Objective-C 2.0 ローカルカテゴリの書き方

@interface Hello : NSObject {
 ...
}




@interface Hello()
- (void)world;
@end

@implementation Hello  // ←()のないメインの実装の中に書く

- (void)world {
}

@end

2010-01-05

2010年 - Smalltalkを体験する年

以前から @sumim さんからさんざん言われていたが、年末に呑んだときに話の流れでこういうことに。Smalltalkのすごさがわかる本書いてよ、といったらパーソナルなツールとなるもの、とても万人に向けてよさを伝える本は(面倒くさくて)書けない、結局one to oneでないとよさは伝えられないよ。ということで、聞いてくれたら答えてくれるそうなので勉強してみようという次第です。どうなることやら。

まずは環境構築からだな。うちにあるSqueak入門読んだほうがいいのかな。一回は読んだ気がしますが。

ともかく悩んだら考える前に聞いて、という夢のような先生なので、期待してます。

ブログ始めました

2010年、今年はブログを始めてみようかと思います。