Hatena::ブログ(Diary)

24/7 twenty-four seven Twitter

東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

Bloglinesで閲読登録 ADD TO Hatena::RSS Subscribe with livedoor Reader Add to Google

mail address

Follow me on twitter.

iPhone アプリケーション

Hatena touch LDR touch TV Listings LCD Clock MyWebClip MyWebClip LITE  Japan Subway Route Map こころくろっく 英辞郎 on the WEB for iPhone(アルク)
i-Radio くるりんぱ性格診断 英辞郎検索ランキング(アルク) kotobank - コトバンク miil

iPad アプリケーション

LCD Clock HD 「超」整理手帳 for the iPad

共著

2011-12-02

CAEmitterLayer でクリスマスは爆発しろ - iOS Advent Calendar 2011

iOS 5 からCAEmitterLayer と CAEmitterCell クラスが iOS でも使えるようになり、パーティクルを簡単に表示することができるようになりました。


これを使ったクリスマスネタが何かできないかと思って、タップするとクリスマスが爆発するゲームを作ってみました。

みんなでクリスマスを爆発させてください。

kishikawakatsumi/ExplodeChristmas - GitHub


ゲームが始まるとクリスマス(っぽいもの)が落ちてくるので……

f:id:KishikawaKatsumi:20111202231641p:image:w320


タップして爆発させてください。

f:id:KishikawaKatsumi:20111202231644p:image:w320

f:id:KishikawaKatsumi:20111202231645p:image:w320


根こそぎ爆発させてください。

f:id:KishikawaKatsumi:20111202231643p:image:w320


f:id:KishikawaKatsumi:20111202231642p:image:w320

2011-11-20

Titanium mobile の KeyChain モジュール TiKeyChainStore を書きました。【添削希望】

UICKeyChainStore を応用して Titanium mobile の KeyChain モジュール TiKeyChainStore を書きました。

kishikawakatsumi/TiKeyChainStore - GitHub


下記のように使います。

var store = tikeychainstore.createKeychainStore({
  service: 'com.kishikawakatsumi.ti' // optional
});

store.setKeyChainItem ({
  key: 'userame',
  value: 'kishikawakatsumi@mac.com'
});

store.setKeyChainItem ({
  key: 'password',
  value: 'password1234'
});

store.synchronize;

Ti.API.info(store.description); // debug print

Titanium のモジュールは初めて書いたので、詳しい方に添削してもらえるとうれしいです。


関連リンク

KeyChain のデータを操作するラッパークラス UICKeyChainStore を書きました。

アップルのサンプルコード GenericKeychain に含まれる KeyChain のラッパー KeychainItemWrapper.m の実装が微妙だったので書きました。

kishikawakatsumi/UICKeyChainStore - GitHub


KeychainItemWrapper クラスには下記で報告されている問題や、

A-Liaison BLOG: KeychainItemWrapper を改造して、複数の Keychain Item に同時にアクセス出来るようにしてみた


下記の箇所でメモリーリークする問題があったり、使い勝手もよくないので、そのまま使うのはおすすめしません。

- (void)resetKeychainItem
{
	OSStatus junk = noErr;
    if (!keychainItemData) 
    {
        self.keychainItemData = [[NSMutableDictionary alloc] init]; // <= メモリーリークする!

というわけで、あたらしく書いて見ました。

使い方

  1. リンクするフレームワークに Security.framework を追加します。
  2. UICKeyChainStore.h と UICKeyChainStore.m をプロジェクトに追加します。

クラスメソッドを使って値を操作する

便利メソッドとしてクラスメソッドを用意してあります。キーと値を指定するだけで簡単に使えます。

サービス名を指定しない場合は自動的に Bundle ID がサービス名になります。


キーと値を指定して値を追加・更新する。

[UICKeyChainStore setString:@"kishikawakatsumi" forKey:@"username"];
[UICKeyChainStore setString:@"password1234" forKey:@"password"];

//=> ["username" = "kishikawakatsumi", "password" = "password1234"]

サービス名を明示的に指定することもできます。

[UICKeyChainStore setString:@"kishikawakatsumi" forKey:@"username" service:@"com.kishikawakatsumi"];
[UICKeyChainStore setString:@"password1234" forKey:@"password" service:@"com.kishikawakatsumi"];

値をキーチェーンから削除するにはキーを指定します。

[UICKeyChainStore removeItemForKey:@"username"];
[UICKeyChainStore removeItemForKey:@"password"];

サービス名を指定していた場合は、サービス名も含めて指定します。

[UICKeyChainStore removeItemForKey:@"username" service:@"com.kishikawakatsumi"];
[UICKeyChainStore removeItemForKey:@"password" service:@"com.kishikawakatsumi"];

KeyChainStore オブジェクトを使って値を操作する

複数の項目を追加・更新する場合は UICKeyChainStore のインスタンスを作成するほうが便利です。

NSUserDefaults のような使い勝手になります。


デフォルトのサービス名 (Bundle ID) の KeyChainStore を作成した場合。

UICKeyChainStore *store = [UICKeyChainStore keyChain];

[store setString:@"kishikawakatsumi@mac.com" forKey:@"username"];
[store setString:@"password1234" forKey:@"password"];

[store synchronize]; // Write to keychain.

サービス名を指定して KeyChainStore を作成した場合。。

UICKeyChainStore *store = [UICKeyChainStore keyChainStoreWithService:@"com.kishikawakatsumi"];

[store removeItemForKey:@"username"];
[store removeItemForKey:@"password"];

[store synchronize]; // Write to keychain.

miil 1.0.1 がリリースされました。

miil

miil miil

miil.me


miil 1.0.1 がリリースされました。


バージョン 1.0.1 の変更点

機能改善

  • ユーザー一覧画面のフォローボタンのタップ領域を拡大し、押しやすくしました。
  • Twitterから友だちを検索する際のUIを改善しました。
  • 現在地以外の位置情報を投稿できるようになりました。
  • お店を新しく登録する際の手順を改善しました。

不具合の修正

  • HOTタイムラインの並び順が更新されない問題を修正しました。
  • フォローボタンが正しく動かない問題を修正しました。
  • ユーザー登録できないことがある問題を修正しました。
  • お店の情報が正しく追加されないことがある問題を修正しました。
  • iPod touchで電話をかける画面が表示されてしまう問題を修正しました。
  • 「お知らせ」を表示する際にクラッシュすることがある問題を修正しました。
  • 「続きを読みこむ…」を押した際にクラッシュすることがある問題を修正しました。
  • 新着の「お知らせ」バッジが表示されないことがある問題を修正しました。

関連リンク


東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

miil 1.0.0 がリリースされました。

miil

miil miil

miil.me


私がプログラムを担当しました、miil 1.0.0 がリリースされました。


食べものの写真を通して「おいしい!」を共有するアプリケーションです。


写真を撮って投稿したり、ほかの人の写真をみたり、

f:id:KishikawaKatsumi:20111120151225j:image:w320


ほかの人の写真をみたり、感想を書き込んだり、

f:id:KishikawaKatsumi:20111120151226j:image:w320


食べたい写真があったら、お店を調べたりできます。

f:id:KishikawaKatsumi:20111120151227j:image:w320


眺めているだけでも楽しい気分になるアプリケーションですので、ぜひダウンロードしてみてください。

関連リンク


東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

2011-09-16

i-Radio 1.2.0 がリリースされました。

i-Radio

i-Radio i-Radio


ネットラジオアプリケーション i-Radio のバージョン 1.2.0 が審査を通過しました。

自動更新購読 (Auto-Renewable subscriptions) による月額プレミアム会員がスタートしました。

プレミアム会員になると、季節ごとのバックナンバーが聴取できるようになるほか、すべての画面で広告が非表示になります。


主な変更点

  • 自動更新購読 (Auto-Renewable subscriptions) によるプレミアム機能の追加

関連リンク

2011-07-15

ColorChooser が便利

f:id:KishikawaKatsumi:20110715085434p:image


カラーピッカーで選択した色を自動的に UIColor や NSColor のコードに変換してくれるユーティリティです。

同様のものに Developer Color Picker がありますが、 それのメニュー常駐版のような感じです。

コードを書いているときにどこからでも呼び出せるので私はこちらのほうが便利だなと思います。

ColorChooser - Pairote Leelaphattarakij

2011-07-12

UINavigationBar に複数の UIBarButtonItem を配置するには

UINavigationBar は基本的に左右 (leftBarButtnItem, rightarButtonItem) に一つずつしかボタンを配置することができません。

しかし、ちょっと工夫をするとその制限を突破することができます。

(まあ物理的なスペースの関係でせいぜい2つか3つがやっとなのですけどね)


方法その1. UIToolbar を UIBarButtonItem として配置し、その中に UIBarButtonItem を並べる

f:id:KishikawaKatsumi:20110712225739p:image


もっとも見た目がキレイに仕上がる方法です。

UINavigationBar の leftBarButtnItem と rightarButtonItem は UIBarButtonItem のインスタンスをそれぞれ1つずつしか代入できませんが、UIToolbar を UIBarButtonItem として作成することで、その UIToolbar に複数のボタンを配置することができるようになります。


UIBarButtonItem *sendButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Send", nil) style:UIBarButtonItemStyleBordered target:self action:@selector(send:)];

UIBarButtonItem *cameraButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:@selector(cancel:)];
cameraButton.style = UIBarButtonItemStyleBordered;

UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

UIToolbar *toolbar = [[MyToolbar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 110.0f, 44.0f)];
toolbar.backgroundColor = [UIColor clearColor];
toolbar.autoresizingMask = UIViewAutoresizingFlexibleHeight;
UIBarButtonItem *toolbarBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:toolbar];
[toolbar release];

toolbar.items = [NSArray arrayWithObjects:space, cameraButton, sendButton, nil];
[space release];
[cameraButton release];
[sendButton release];

self.navigationItem.rightBarButtonItem = toolbarBarButtonItem;
[toolbarBarButtonItem release];

ただ、標準の UIToolbar の外観は UINavigationBar の外観と微妙な差異があるので、このままでは境界が目立ってしまいます。

f:id:KishikawaKatsumi:20110712234728p:image


そこで UIToolbar のサブクラスを作成し、空の drawRect: メソッドでオーバーライドし、標準の描画を無効にします。

@interface MyToolbar : UIToolbar
@end

@implementation MyToolbar

- (void)drawRect:(CGRect)rect {
    
}

@end

すると、このような状態になります。

f:id:KishikawaKatsumi:20110712235526p:image


真っ黒になってしまったので、背景色を透明に設定します。

drawRect: メソッドの処理は backgroundColor と無関係というのがミソですね。

toolbar.backgroundColor = [UIColor clearColor];

キレイになりました。

f:id:KishikawaKatsumi:20110713000034p:image


もし、横方向の画面をサポートする場合、ナビゲーションバーは横方向では 30 ピクセルの幅に変わりますので、ツールバーの autoresizingMask プロパティに UIViewAutoresizingFlexibleHeight を設定しておきましょう。

toolbar.autoresizingMask = UIViewAutoresizingFlexibleHeight;

f:id:KishikawaKatsumi:20110713000931p:image


UIViewAutoresizingFlexibleHeight を指定しない場合は下のようになります。すこしボタンの大きさがアンバランスですね。

f:id:KishikawaKatsumi:20110713000937p:image


色をつけると違いが分かりやすくなります。

f:id:KishikawaKatsumi:20110713000935p:image

f:id:KishikawaKatsumi:20110713000934p:image


tintColor を設定すれば色も変えられます。

f:id:KishikawaKatsumi:20110713005827p:image


方法その2. UISegmentedControl をボタンのように使用する

標準のメールアプリでも採用されている方法です。

メールアプリの「前へ」「次へ」のように同じような動作をするボタンを並べる場合は良い方法だと思います。

f:id:KishikawaKatsumi:20110713002751p:image:w320


titleView プロパティに乗せると3つのボタンを並べても余裕があります。

f:id:KishikawaKatsumi:20110713002748p:image:w320


UISegmentedControl をボタンとして使用するには、momentary プロパティを YES に、アクションは UIControlEventValueChanged を設定します。

segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.momentary = YES;
segmentedControl.frame = CGRectMake(segmentedControl.frame.origin.x, segmentedControl.frame.origin.y, segmentedControl.frame.size.width + 16.0f * [items count], segmentedControl.frame.size.height);
[segmentedControl addTarget:self action:@selector(segmentedControlAction:) forControlEvents:UIControlEventValueChanged];
[self.navigationItem setTitleView:segmentedControl];
[segmentedControl release];

方法その3. UIToolbar を上部のナビゲーションバーの位置に配置する

簡単ですがオススメしません。

というのも UIToolbar は画面の下部に配置するようにデザインされているため、上部に配置するとどうしても外観に違和感がでてしまうからです。

iOS 4.x までの iPhone の場合。iPad のツールバーは上下どちらに配置してもいいようにデザインされている。)


f:id:KishikawaKatsumi:20110713004832p:image

ナビゲーションバーの位置に配置したツールバー。

ステータスバーとの境界が不自然ですね。

2011-05-05

NSNull のインスタンスは nil として振舞ってくれると嬉しいなって


とか思ってたのですが、そう考える人はやっぱりほかにもいるようです。



たとえば私がいちばん面倒だなと思うのはjson-frameworkがnullをNSNullにマッピングするので(nilはNSArrayやNSDictionaryに格納できないため)でWeb APIからのレスポンスをParseする際に、値がセットされるときとnullがセットされるときと両方あるような場合、ハンドリングがとたんに面倒になるのですね。

 NSString *results = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
 NSDictionary *dic = [results JSONValue];
 NSString *shortURL = [[[dic objectForKey:@"results"] objectForKey:longURL] objectForKey:@"shortUrl"];

上記の場合、longURL の値が NSNull だったとすると objectForKey: の呼び出しが失敗してクラッシュします。

このとき NSNull が nil だとしたら、nil へのメッセージは単に無視されるので問題ないわけなのでそうなっていたら便利なのにという話です。


というわけで、下記のようなカテゴリをどこかに書いておくと、NSNull へのメッセージはすべて無視されるので、まるで nil のように扱えて便利です。

何をしているかというと、メッセージフォワーディングの仕組みが動作するように methodSignatureForSelector: および forwardInvocation: をオーバーライドします。

そうすると存在しないメソッドを呼びだそうとするとこれらのメソッドが呼ばれるので、forwardInvocation: メソッドで NSNull に存在しないメソッドの呼び出しは無視するように処理を変更しています。

[参考]Does Objective-C use short-circuit evaluation? - Stack Overflow

@implementation NSNull(IgnoreMessages)

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([self respondsToSelector:[anInvocation selector]]) {
        [anInvocation invokeWithTarget:self];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *sig=[[NSNull class] instanceMethodSignatureForSelector:aSelector];
    // Just return some meaningless signature
    if (sig == nil) {
        sig = [NSMethodSignature signatureWithObjCTypes:"@^v^c"];
    }
    
    return sig;
}

@end

東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

2011-04-04

MKMapView に CATransform3D を適用するときの注意



@さんがつぶやいてたので気になって調べてみました。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0f / -500.0f;
    transform = CATransform3DRotate(transform, 60.0f * M_PI / 180.0f, 1.0f, 0.0f, 0.0f);
    
    mapView.layer.transform = transform;
}

こんなふうに書いてみたところ、どうもズーム機能が正常に動作しなくなるようです。

(ズームはするけど拡大率に合わせて再描画してくれない)


で、いろいろ試した結果、どうやら mapView の親ビューのレイヤーに transform を適用した上で、mapView のレイヤーにはその逆行列を適用することで打ち消してあげると正しく動作するようです。

(単純に親ビューのレイヤーに適用するだけではダメ。親ビューのレイヤーに適用した transform は自動的にサブビューのレイヤーにも適用されるので。)

下記がコード例です。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0f / -500.0f;
    transform = CATransform3DRotate(transform, 60.0f * M_PI / 180.0f, 1.0f, 0.0f, 0.0f);
    
    contentView.layer.transform = transform;
    
    // mapView に逆行列を適用する
    CATransform3D t = CATransform3DInvert(transform);
    mapView.layer.transform = t;
}

実行した結果は下のようになります。ちゃんとズームできてますね。

f:id:KishikawaKatsumi:20110404235137p:image


ちなみに、ズームできなくなるのは行列の m34 要素を変更したときのみで、単に回転やスケールするだけなら問題ないぽいです。


東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

2011-03-29

kotobank for iPhone 1.0.0 がリリースされました。

kotobank - コトバンク

kotobank - コトバンク kotobank - コトバンク

kotobank for iPhone | genesix


私がプログラムを担当しました、kotobank for iPhone 1.0.0 がリリースされました。


データを内部に持ち、オフラインで使用できる辞書アプリケーションです。

このアプリケーションの特長は、複数の辞書を一度に横断検索できる点です。

初期状態では付属しているポケットプログレッシブ国語辞典だけの検索になりますが、追加の辞書を購入することでひとつの言葉をいろいろな辞書で一度に調べられます。

以下が初期状態の検索結果です。

f:id:KishikawaKatsumi:20110330011912p:image:w320


現在、購入可能な辞書をすべてインストールした場合、同じ語でも次のような結果になります。

f:id:KishikawaKatsumi:20110330011906p:image:w320


「企業がわかる事典」など、普段あまり使わない辞書に意外な結果が出ておもしろかったりします。


検索結果を選択すると、詳しい意味を見ることができます。

この画面からは、調べた単語を単語帳に登録したり、メールで送信することができます。

f:id:KishikawaKatsumi:20110330011907p:image:w320


また、この画面からさらに気になる言葉を選択して、検索しなおすことが可能です。

この機能でどんどん言葉を検索していくと、ついつい時間をわすれてしまいそうになります。

f:id:KishikawaKatsumi:20110330011913p:image:w320


単語帳に登録した言葉は、単語帳タブの画面から見ることができます。

f:id:KishikawaKatsumi:20110330011908p:image:w320


アプリケーションのストアから辞書を購入して追加することができます。

現在は「プログレッシブ和英中辞典 第3版」「プログレッシブ英和中辞典 第4版」「企業がわかる事典」の3つが購入できます。

和英と英和辞書はそれぞれ 1,600 円ですが、「英和中辞典セット」という商品を購入すると、2,000 円で両方の辞書を一度に購入できるのでおトクです。

f:id:KishikawaKatsumi:20110330011909p:image:w320 f:id:KishikawaKatsumi:20110330011914p:image:w320


そのほか、普段あまり使用しない辞書は検索対象外にしたり、ひとつの辞書だけで検索したりといった設定ができます。

f:id:KishikawaKatsumi:20110330011910p:image:w320 f:id:KishikawaKatsumi:20110330011911p:image:w320


ということで、辞書を追加していくことでどんどん調べる楽しさが増えていくアプリケーションです。

ぜひダウンロードして使ってみてくださいませ。


関連リンク


東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

2011-03-24

LCD Clock HD 1.1.2 がリリースされました。

LCD Clock HD

LCD Clock HD LCD Clock HD

バージョン 1.1.2 がアップルの審査を通過しました。

iOS 4.3の動作と、日本以外の国において2011年後半の移動休日のデータを更新しました。

変更点

  • iOS 4.3の動作を確認しました。
  • 日本以外の国において2011年後半の移動休日のデータを更新しました。

東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

2011-03-17

LCD Clock 4.0.2 をリリースしました。

LCD Clock

LCD Clock LCD Clock

iOS 4.3の動作と、日本以外の国において2011年後半の移動休日のデータを更新しました。

変更点

  • iOS 4.3の動作を確認しました。
  • 日本以外の国において2011年後半の移動休日のデータを更新しました。

東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン

iPhone アプリにおいて Interface Builder を使って Grouped Style の UITableView を作るときは separatorStyle の値に注意

Grouped スタイルのテーブルビューを使用した iPhone アプリケーションの中に、下の画像のように先頭セクションの区切り線が2重に表示されているものをチラホラ見かけます。

実用上の問題は無いのですが、ちょっと不恰好なので気になりますよね。


f:id:KishikawaKatsumi:20110317211514p:image


この現象は、UITableView の separatorStyle に UITableViewCellSeparatorStyleSingleLineEtched が指定されていることが原因で発生します。

コードでインスタンスを生成した場合の separatorStyle デフォルト値は UITableViewCellSeparatorStyleSingleLine なのですが、Interface Builder で UITableView を Grouped スタイルで作成した場合はデフォルト値として UITableViewCellSeparatorStyleSingleLineEtched が自動的に選択されるようになりました。

(もともとはそんなことはなかったのですが、UITableViewCellSeparatorStyleSingleLineEtched が iOS SDK 3.2 から導入され、おそらくそのあたりのタイミングで動作が変更されたようです。)


ということですので、iPhone の場合に Grouped スタイルのテーブルビューを Interface Builder を使って作成するときは、separatorStyle の値を UITableViewCellSeparatorStyleSingleLine など、UITableViewCellSeparatorStyleSingleLineEtched 以外に設定しましょう。

コードでインスタンスを生成した場合のデフォルト値は UITableViewCellSeparatorStyleSingleLine ですので問題はありません。


f:id:KishikawaKatsumi:20110317211517p:image


公式のドキュメントによる言及が見つからないのですが、UITableViewCellSeparatorStyleSingleLineEtchedは(おそらく)iPad 専用の値です。

次のように iPad で Grouped Style のテーブルに対して指定した場合はキレイにハマります。


f:id:KishikawaKatsumi:20110317211516p:image


というわけで、コードで作る場合にはデフォルト値はドキュメントに書いてあるとおりなのですが、Interface Builder を使って作る場合にはデフォルト値は (IB が空気を読んで?) ドキュメントと異なる場合が多いので注意したほうがいいですね。

Interface Builder で作った場合とコードで書いた場合のデフォルト値の違いは、ほかにも各種ビューの backgroundColor や autoresizingMask などがありますので、余計な色が付いていないかどうかなど、きちんと確認したほうがいいでしょう。


東日本大震災緊急支援募金募集中。国際NGOワールド・ビジョン・ジャパン