— boreal-kiss.com

Archive
Tag "iPhone"

Processingでちまちま描いていたSimian Mobile Discoの最新アルバム、Unpatternsのカバーアートに採用されました。CD、レコードともに盤を回転させるとカバーの模様と干渉してモアレが生成される仕組みになっていて、ジャケットを鑑賞するだけでも楽しめると思います。元々の図柄はBridget RileyのRiley Wavesを再現したものになっています。

同時にiPhoneアプリケーションの方もコラボレーションさせていただきました。こちらはMoiréアプリの内容にいくつか新しい形状を加えた形になっています。もちろん最新アルバム収録曲全て聴けます。

Read More

テンプレートにサブグループ(グループ内グループ)を追加する方法は、Appleのデフォルトテンプレートには実践している例がなく、さらにテンプレートの仕様についても何も情報がないため長いこと謎だった。が、判明。例えば以下のようなディレクトリ構造のままテンプレートにSomeClass.mファイルを追加したいとする。

Classes/SomeClass/SomeClass.m

この場合、Definitionsパートに次のように記述すればディレクトリ構造を保持したままテンプレートに追加することができる。

<key>Definitions</key>
<dict>
	<key>Classes/SomeClass/SomeClass.m</key>
	<dict>
		<key>Group</key>
		<array>
			<string>Classes</string>
			<string>SomeClass</string>
		</array>
		<key>Path</key>
		<string>Classes/SomeClass/SomeClass.m</string>
	</dict>
</dict>

Nodesパートは関連するKeyネームを追加するだけで特に目新しい変更はない。

<key>Nodes</key>
<array>
	<string>Classes/SomeClass/SomeClass.m</string>
</array>

サブグループを追加したテンプレートの一例はgithubに置いてある。テンプレートの詳細については以下のリンク先を参照ください。

Read More

Xcode 4用のユーザーテンプレートの作り方がだいぶわかってきたのでまとめた。余裕ができたら日本語化する予定。

テンプレートを改変をする際に注意すべきこと

TemplateInfo.plist (新規プロジェクト作成時にXcode 4が最初に読み込む設定ファイル)の改変には細心の注意を。不正なデータ構造を残したままXcode 4に読み込ませると最悪の場合、無関係なディレクトリを消去してしまう等、作業環境に悪影響を与える可能性がある。詳細は上記ブログ記事を参照ください。

Downloads

iPhone用のサンプルは以下に置いてある。

Read More

iPhone、iPad用にアイコンをリサイズするMacアプリケーションIconUtilityをver. 0.9.3にアップデート。画像縮小時の質感のコントロールできるようになりました。具体的にはCoreGraphicsが描画時に使用するinterpolationアルゴリズムを選択できるようにしています1。コアになっているのは以下の関数。

void CGContextSetInterpolationQuality (
   CGContextRef c,
   CGInterpolationQuality quality
);
 
enum CGInterpolationQuality {
   kCGInterpolationDefault = 0,
   kCGInterpolationNone = 1,
   kCGInterpolationLow = 2,
   kCGInterpolationMedium = 4,
   kCGInterpolationHigh = 3
};
typedef enum CGInterpolationQuality CGInterpolationQuality;

CGInterpolationQualityの具体的な使用例はResize a UIImage the right way — Trevor’s Bike Shedで紹介されているUIImage+Resize.h, UIImage+Resize.mが参考になります。

以下IconUtility ver.0.9.3で作成したアイコン例を挙げておきます。

– None (kCGInterpolationNone)を使用した場合のIcon@2x.png

– High (kCGInterpolationHigh)を使用した場合のIcon@2x.png

ソースとアプリケーション本体は以下に置いてあります。

Footnotes

  1. 以前のバージョンではkCGInterpolationDefaultのみを使用。 []
Read More

画像をドロップするとiPhone/iPad用のアイコン用にリサイズするMac用アプリケーションです。対応サイズと出力ファイル名は以下の通り1

  • Icon.png – 57×57ピクセルのiPhoneアイコン
  • Icon@2x.png – 114×114ピクセルのiPhone 4アイコン
  • Icon-72.png – 72×72ピクセルのiPadアイコン
  • Icon-Small.png – 29×29ピクセルのiPhoneセッティングアイコン
  • Icon-Small@2x.png – 58×58ピクセルのiPhone 4セッティングアイコン
  • Icon-Small-50.png – 50×50ピクセルのiPadセッティングアイコン

ソースとアプリケーション本体は以下に置いてあります。

Footnotes

  1. Updating for the iPhone 4 retinal display – Blog – Use Your Loaf []
Read More

Important note at July 05, 2010

It is found the problem below does not come from SDK but ME. Specifically when implementing UITabBarController, I’ve ignored to set its view’s autoresizesSubviews property to YES. The repository of BKTabBarController at github.com will be also closed soon.

——————- The original artice stats here. ——————-

SDK 3.2ではiPadをターゲットにした場合UITabBarControllerが正しく動作しない。具体的に言うと以下のような問題が発生する。

  • デバイスの回転が生じた際、配下のUIViewControllerのビューフレームが再配置されない。
  • 回転後に強制的に子ビューのフレームを変更すると、子ビュー中のボタン(UINabigationBarの場合右側ボタンのみ)が動作しなくなる。

全く同じ現象に悩んでいる人が他にもいたので自分の勘違いというわけではなさそうだ。

View controllers inside tab bar controller not auto-resizing on rotation – Stack Overflow

もし勘違いでないとすると結構な問題だ。というのもiPadではPortraitとLandscapeどちらのデバイス方向にも対応したアップリケーションでなければ提出できないのだが、UITabBarControllerを使った場合回転時に全く使い物にならないアプリケーションになってしまうからだ。

BKTabBarController

そこで上記問題点を解消するようなTabBarControllerクラスを作った。次回SDKアップデートでUITabBarControllerの不具合が修正されるまでは役立つと思う。UITabBarControllerと同じインターフェースで、現時点で実装してあるものを以下に示す(タブのカスタマイズ系は未実装)。

Properties / methods

@interface BKTabBarController : UIViewController {
 
}
 
@property (readonly, retain) UITabBar *tabBar;
@property (nonatomic, copy) NSArray *viewControllers;
@property (nonatomic, assign) NSUInteger selectedIndex;
@property (nonatomic, assign) UIViewController *selectedViewController;
@property (nonatomic, assign) id <BKTabBarControllerDelegate> delegate;
 
-(void)setViewControllers:(NSArray *)controllers animated:(BOOL)animated;
@end

Delegate

@protocol BKTabBarControllerDelegate <NSObject>
@optional
 
-(void)bkTabBarController:(BKTabBarController *)tabBarController 
	didSelectViewController:(UIViewController *)viewController;
-(BOOL)bkTabBarController:(BKTabBarController *)tabBarController
	shouldSelectViewController:(UIViewController *)viewController;
@end

ソースコードを含むサンプルプロジェクトとスタティックライブラリ化したライブラリは以下においてあるのでご自由にお使いください。

[イントロダクション]

cocos2d for iPhoneはiPhoneアプリケーション製作用のフレームワークで、主に2Dゲームを作る際の基盤に用いられているようである。UIKitより使い勝手が良いと思える点は以下の通り。

  1. オブジェクトの扱い方がFlashの感覚にかなり近い。Cocoa touch特有のframeやboundsを気にしなくてよく、-[Sprite addChild:]などおなじみの操作も行える。
  2. メモリ管理をほとんど気にしなくてよい。cocos2dオブジェクトに関しては内部で適切に処理されるようになっている(ようである)。
  3. シーン遷移機能が標準装備されている。エフェクトの種類も豊富。

個人的にはFlash的に操作できるという点が一番の恩恵だと思っており、最近はXcodeのプロジェクト作成時にcocos2d用テンプレートしか使っていない。テンプレートを使うのであれば例えばCocos2d – 2D OpenGL for the iPhone made Easy. Part 1.に簡素なものがある。自分で作るのであれば【Xcode】設定しておくと便利なカスタマイズいろいろが参考になる。

[追記: 2009/09/02]

cocos2d for iPhone v0.8.1-betaよりプロジェクトテンプレートが用意されている。詳しくはrelease_notes:0_8_1_beta [cocos2d for iPhone]のTemplateの項参照。

[本題]

このCocos2d for iPhoneだが、ライブラリの状態で配布されていない。そのまま使用するのであれば大量のcocos2dソースファイルをプロジェクトに追加する形になる。これはコンパイルに結構時間がかかるし、ソースファイルに誤って書き込んでしまう可能性がある。そこでcocos2dを静的ライブラリ化することにする。以下で使用したのはcocos2d for iPhone v0.8。

[手順0. その前に]

実は、単純に静的ライブラリを作ってもiPhoneシミュレータとiPhone実機両方で使用することができない。というのはiPhoneシミュレータとiPhone実機のアーキテクチャ(ハードの構造)が異なるためである。したがって両者で動くようなライブラリを作るのには一工夫必要となる。

[手順1. iPhoneシミュレータ用静的ライブラリを作る]

  1. とりあえずiPhoneシミュレータ用を作る(iPhone用が先でもかまわない)。cocos2dプロジェクト内に新規Static Libraryを追加(ターゲット追加 > 新規ターゲット > Cocoa touch Static Library)、名前を”cocos2d-simulator”とする(名前はシミュレータ用であると自分でわかればなんでもよい)。
  2. 必要なファイル(cocos2dだけであればcocos2dフォルダ内のファイル一式)をターゲット配下に追加する。具体的には「ヘッダをコピー」にヘッダファイルを、「ソースをコンパイル」にソースファイルを、「バイナリをライブラリにリンク」に使用フレームワーク(Foundation, UIKit, CoreGraphics, OpenGLES, QuartzCoreの5種類)を追加する。
  3. (追記 2010/05/05: フレームワークの追加は不要。これらは必要に応じてプロジェクトに追加する方が適切だと思う)

  4. ターゲット情報のアーキテクチャの項目のベースSDKを”iPhone Simulator 3.0″にする(バージョンはお好みで)。
  5. ターゲットを”cocos2d-simulator”にしてビルドするとbuild配下に”libcocos2d-simulator.a”が出来ている(シミュレータ用静的ライブラリ完成)。ReleaseバージョンやDebugバージョンなどはお好みで。

[手順2. iPhoneOS用静的ライブラリを作る]

上記シミュレータ用ライブラリ作成手順とほぼ同じ。

  • cocos2dプロジェクト内に新規Static Libraryを追加、名前を”cocos2d-iphoneos”とする(名前は適宜)。
  • ターゲット配下に必要なファイルを追加する(内容は上記シミュレータ用のものと同様)。
  • ターゲット情報のアーキテクチャの項目のベースSDKを”iPhone Device 3.0″にする(バージョンはお好みで)
  • ターゲットをビルドして”libcocos2d-iphoneos.a”を作成(iPhone用静的ライブラリ完成)。

[手順3. 上記二種類の静的ライブラリをマージする]

“lipo”と呼ばれるコマンドラインツールがマージをしてくれる。詳細はiPhone OS用のほぼFrameworkの作り方How to (almost) create your own iPhone OS frameworkが詳しい。

  1. cocos2dプロジェクト内に新規Shell Script Targetを追加する(ターゲット追加 > 新規ターゲット > Other > Shell Script Target)、名前を”cocos2d-0.8″とする(名前は自分で識別できれば何でもかまわない)。
  2. ターゲット配下の”スクリプトを実行”に以下のコマンドを記述する。コマンドを注意深く見てもらえばわかると思うが、シミュレータ・iPhone用のライブラリ名は自分が作成したものに適宜変更する必要がある。マージ後のライブラリ名はお好みで。
  3. rm -rf build/${BUILD_STYLE}-iphoneos/cocos2d-0.8-${BUILD_STYLE}.a
    
    lipo -create "build/${BUILD_STYLE}-iphoneos/libcocos2d-iphoneos.a" \
    "build/${BUILD_STYLE}-iphonesimulator/libcocos2d-simulator.a" \
    -output "build/${BUILD_STYLE}-iphoneos/cocos2d-0.8-${BUILD_STYLE}.a"
    

  4. ターゲットを”cocos2d-0.8″に設定してビルドするとマージされた静的ライブラリが作成される。上記のコマンドの例だと例えば”build/Release-iphoneos/libcocos2d-iphoneos.a”と”build/Release-iphonesimulator/libcocos2d-simulator.a”のファイルをマージして”build/Release-iphoneos/cocos2d-0.8-Release.a”が作成されることになる。マージされたライブラリはシミュレータでもiPhone実機でも使うことができる。

[実際の使用方法]

上記手順でシミュレータでもiPhone実機でも使える静的ライブラリ”cocos2d-0.8-Release.a”ができているとする。このファイルだけでcocos2dが使えるのかと思いきや、ヘッダーファイルの実態への参照を用意しなくてはいけない。具体的には以下の二点の作業を行えばプロジェクト内でcocos2dが動作する。

  1. プロジェクトに”cocos2d-0.8-Release.a”を(例えばFrameworksの項目に)追加。
  2. プロジェクト情報のヘッダ検索パスにcocos2dプロジェクト全体を追加(ファインダーからドラッグでok)。ヘッダーファイルのあるcocos2dフォルダだけでもよい(要はどこにcocos2dに関係したヘッダーファイルがあるかXcodeに教える必要があるというだけである)。ヘッダ検索オプションの”再帰的”にチェックを忘れずに。
Read More

まとめ

  • -[NSObject performSelector:]の返り値として不適切なものが存在する。
  • それら不適切なものを扱う場合の対処法について。

イントロダクション

NSObjectのインスタンスメソッド

- (void)performSelector:(SEL) aSelector

はvoid型となっているが、「引数にセットされたメソッドの返り値」を自分の返り値に持つことができる。ただしその場合、-[NSObject performSelector:]の返り値はid型(オブジェクトポインタ)になるので適切にキャストしてやる必要がある。例えば、以下のようなNSStringを返すメソッドを持つTest1クラスを考える。

@implementation Test1
 
-(NSString *)stringValue{
	return @"Hello";
}
 
@end

このTest1クラスに-[NSObject performSelector:]を使って-[Test1 stringValue]を呼び、NSStringにキャストして返り値を受け取るとたしかに@”Hello”が返ってきていることがわかる。

Test1 *test1 = [[Test1 alloc] init];
NSString *stringValue = (NSString *)[test1 performSelector:@selector(stringValue)];
NSLog(@"%@", stringValue);// Hello

本題

-[NSObject performSelector:]の返り値はid型であり、id型はオブジェクトへのポインタであると説明した。つまり、-[NSObject performSelector:]は「オブジェクトではないものを返り値とするメソッド」の返り値を受け取ることができない可能性があることがわかる。例を見てみよう。Test2クラスに以下のようなメソッドがあるとする。どのメソッドの返り値もオブジェクトではない。

@implementation Test2
 
-(BOOL)boolValue{
	return YES;
}
 
-(int)intValue{
	return 10;
}
 
-(float)floatValue{
	return 2.0;
}
 
-(CGPoint)point{
	return CGPointMake(100.0, 100.0);
}
 
@end

先ほどと同様にこれらのメソッドを-[NSObject performSelector:]を使って呼び出し、返り値を確認すると以下のような結果になった。

Test2 *test2 = [[Test2 alloc] init];
 
//warning: cast from pointer to integer of different size
BOOL boolValue = (BOOL)[test2 performSelector:@selector(boolValue)];
NSLog(@"%i", boolValue);// 1
 
int intValue = (int)[test2 performSelector:@selector(intValue)];
NSLog(@"%i", intValue);// 10
 
//error: pointer value used where a floating point value was expected
float floatValue = (float)[test2 performSelector:@selector(floatValue)];
NSLog(@"%f", floatValue);
 
//error: conversion to non-scalar type requested
CGPoint point = (CGPoint)[test2 performSelector:@selector(point)];
NSLog(@"%@", NSStringFromCGPoint(point));

結果をまとめると以下のようになる。

  • 返り値BOOLについては警告が出たが返り値の受け取りができた。
  • 返り値intについては警告は出ず返り値の受け取りができた。
  • 返り値floatについてはコンパイルエラーが生じ実行できなかった。
  • 返り値CGPointについてはコンパイルエラーが生じ実行できなかった。

対処法

上記のテスト結果から、-[NSObject performSelector:]から「オブジェクトではないものを返り値とするメソッド」の返り値を受け取るためには何かしらの工夫をしなければならないことがわかった(int型・BOOL型などの例外もある)。以下に二種類の対処法を挙げておく。

  1. -[NSObject performSelector:]で呼び出すメソッドの返り値をオブジェクトにしておく。
  2. -[NSObject performSelector:]の代わりに[NSInvocation invoke]を用いる。

順に見てみよう。

対処法1

二つ目の対処法より簡単である。返り値int, BOOL, floatについてはNSNumberオブジェクトによるラッピング、返り値CGPoint(CGRect, CGSizeなども含む)についてはNSStringオブジェクトに変換することで簡単に対処できる。以下に、Test2クラスの4メソッドの返り値を全てオブジェクトに変更したTest3クラスを挙げる。

@implementation Test3
 
-(NSNumber *)boolValue{
	return [NSNumber numberWithBool:YES];
}
 
-(NSNumber *)intValue{
	return [NSNumber numberWithInt:10];
}
 
-(NSNumber *)floatValue{
	return [NSNumber numberWithFloat:2.0];
}
 
-(NSString *)point{
	return NSStringFromCGPoint(CGPointMake(100.0, 100.0));
}
 
@end

この場合、各メソッドの返り値はオブジェクトであるため、それらオブジェクトから必要な値を復元してやればよい。

Test3 *test3 = [[Test3 alloc] init];
 
BOOL boolValue = [[test3 performSelector:@selector(boolValue)] boolValue];
NSLog(@"%i", boolValue2);// 1
 
int intValue = [[test3 performSelector:@selector(intValue)] intValue];
NSLog(@"%i", intValue2);// 10
 
float floatValue = [[test3 performSelector:@selector(floatValue)] floatValue];
NSLog(@"%f", floatValue2);// 2.000000
 
CGPoint point = CGPointFromString([test3 performSelector:@selector(point)]);
NSLog(@"%@", NSStringFromCGPoint(point2));// {100, 100}

対処法2

-[NSObject performSelector:]の代わりにNSInvocationを用いると、返り値がオブジェクトであろうとなかろうと受け取ることが可能になる。例えば、-[Test2 floatValue]の返り値を受け取る場合には、以下のような手続きをとる。

Test2 *test2 = [[Test2 alloc] init];
 
float floatValue;
NSMethodSignature *aSigniture 
        = [[test2 class] instanceMethodSignatureForSelector:@selector(floatValue)];
NSInvocation *anInvocation 
        = [NSInvocation invocationWithMethodSignature:aSigniture];
[anInvocation setSelector:@selector(floatValue)];
[anInvocation setTarget:test2];
[anInvocation invoke];
[anInvocation getReturnValue:&floatValue];
NSLog(@"%f", floatValue);// 2.000000

NSInvocationを用いると汎用性は高くなるが、一般的にソースが煩雑になる。

参考

Read More

KanjiName

完全外国人向けアプリケーションをリリースしました。ユーザーの漢字名が載った和風な名札を作成、フォトライブラリの写真上に載せてオリジナルフォトを作成します。漢字には青柳衡山フォント2を使用、イラストレーションは毒乙女に作成いただきました。両氏に感謝。

アプリケーション詳細はこちら。
» KanjiName – Your Japanese Name

Read More

NSCNSC

Nespresso Stock Checkerに新機能を追加しました。GPS機能を使って最寄りのNespressoブティックを検索します。日本は17店舗あるのできっと役に立つと思います(USは7店舗)。

アプリケーション詳細はこちら。
» Nespresso Stock Checker

Read More