株式会社ブリッジ・メタウェア
(株)ブリッジ・メタウェアの社員ブログです。
開発していく中での発見や情報を発信していきます!

iOS3.2からUIBezierPathが利用できるようになりました。
2次元グラフィックを扱う人にとっては朗報ですね。
ところが、実際にUIBezierPathを使ってプログラミングしていたら驚くべきことが分りました。

UIBezierPathを使って多めの線分(3000本)を一気に描画してみました。

(1)普通のケース

- (void)drawRect:(CGRect)rect {
// 諸々描画準備

UIBezierPath *path = [[UIBezierPath alloc]init];
//path.lineWidth = 2; // 2ptの太線にする(今はコメントアウトしておく)
for (int i = 0; i < 3000; i++) {
  double sx = (rand() % 10) / 10.0 * w;
  double sy = (rand() % 10) / 10.0 * h;
  double ex = (rand() % 10) / 10.0 * w;
  double ey = (rand() % 10) / 10.0 * h;
  [path moveToPoint:CGPointMake(sx, sy)];
  [path addLineToPoint:CGPointMake(ex, ey)];
}
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);
NSTimeInterval started = [[NSDate date] timeIntervalSinceReferenceDate];
[path stroke];
NSLog(@"done:%f", ([[NSDate date] timeIntervalSinceReferenceDate] - started) * 1000);
}

実行結果は

>done:265.557945

300ミリ秒弱、ちょっと遅い感じもしますが、、、こんなものでしょうか。

(2)太線にしたケース
上のコードの以下の部分を有効にしてみます。

path.lineWidth = 2; // 2ptの太線にする

実行結果は

>done:178170.634985

え?180秒?3分掛ってる?何かの間違いか?もしや、、これはJavaでも散々問題が発生したアレか?
試しにアンチエイリアスをオフる。

実行結果は

>done:809.293985

うぅ、やっぱり。
大量のグラフィックを描画する場合には、アンチイリアスが必要なものとそうでないものを分けて描画しましょう。

方法はこんな感じです。

// アンチエイリアスをOFFにする。
CGContextSetAllowsAntialiasing(context, false);
CGContextSetShouldAntialias(context, false);

せっかくの美しい画面がジャギジャギですが、背に腹はかえられません。
何かもっと良い方法があるに違いないのですが、今のところ分りません。

 

|trackbacks(3) |18:45 2010/11/18
未分類  falcon

Appleは、iPhone4のアンテナ感度がどうしたこうしたという問題を解決するために、何種類かのiPhone専用ケースを無償配布しました。その中で恐らく一番人気だったのが「バンパー」。確かApple純正ですよね?隙間なくキレイに収まって素敵です。
 
んが、しかし!!同じくApple純正のVGAアダプターが刺さらないじゃないかー!!
一見するとちゃんと刺さってるように見えるんですが、ケースの厚みの分だけ浮いてます。VGAアダプターの根っこがちょこっと太いんです。

これではVGA出力できませんよね。あまりにシドイ…小一時間悩みました。VGA出力できないみなさん、ひょっとしたら原因は「バンパー」かもしれませんよ。
 
「タダより高いものはない」
 

|trackbacks(0) |21:24 2010/11/08

サッカーワールドカップが遠い昔のことのように思えます。
当時、ワールドカップ向けのアプリがたくさんリリースされていました。
有名どころとしてはバーチャルブブゼラでしょうか。無料版、有料版が用意されていて、有料版はただ音が大きい(笑)というお遊びアプリでした。
私もこれに負けじと、イエロー・レッドカードなるアプリを申請しました。
アプリを起動すると下のような画面が表示されて、レッドカードかイエローカードを選択するとホイッスルの音がして画面が真っ赤、または真っ黄色になる、という実にナイスなアプリでした。
スポーツバーでみんながこのアプリで遊んでいるところが目に浮かびました…

ところが、アップルのレビューでRejectされていまいました。Rejectの理由は、噂の「機能無し」でした!
おおいに笑わせていただきました。が、もう少し洒落を分ってくれてもいいですよね!

|trackbacks(1) |15:47 2010/11/05

OpenGLでぶんぶんループを回っているようなアプリは、かなりの勢いで電池を消費するようです。
プレイヤーが考えている時間が長いパズルゲームを作ってしまったので、プレイしている間に消費電力を抑える工夫が必要でした。
そこで一定の間操作が無かったらOpenGLのループを回さない、というごく単純な戦略をとりました。

// アニメーション開始
- (void)startAnimation {
  // 動作中のタイマーがあったら停止
  if (animationTimer != nil && [animationTimer isValid]) {
    [animationTimer invalidate];
    animationTimer = nil;
  }
  // タイマー開始時間をメモ
  startTime = [NSDate timeIntervalSinceReferenceData];

  // 描画タイマー開始(30fpsをメドで再描画)
  animationTimer =
    [NSTimer scheduledTimerWithTimeInterval:1.0/30
          target:self selector:@selector(draw) userInfo:nil repeats:TRUE];
}

// アニメーション停止
- (void)stopAnimation {
  if (animationTimer != nil && [animationTimer isValid]) {
    [animationTimer invalidate];
  }
  animationTimer = nil;
}

// ドラッグイベントハンドラ
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  // 操作時間更新
  startTime = [NSDate timeIntervalSinceReferenceDate];
  // ドラッグの処理
}

// 描画メソド
- (void)draw{
  // オブジェクトの描画

  NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
  NSTimeInterval interval = now - startTime;
  // 何もしていない時間が5秒あったらループ停止
  if (interval > 5) {
    [self stopAnimation];
  }
}

こんな感じでアニメーションを停止するようにしました。
これで触っていないときに電池の減りを抑えることができました。

|trackbacks(2) |15:08

今回はiPhone/iPadアプリ内でXMLをパースする方法について書いてみます。
私の場合、iPhone/iPadでXML形式のデータを扱うのは主に以下のケースです。

  1. iPhone/iPad内に保存されたアプリ独自のデータを読込みする場合
  2. サーバ(Servlet)と通信する場合

まずはDOMでいくか、SAXでいくか選択します。小さいデータならDOMが扱いやすいので、普通にDOM形式で読みこんでしまいます。
問題になるのは、ちょっと大きめのデータを扱う場合で、DOM形式で読みこんでから自分のオブジェクトに変換したのでは一時的に多くのメモリを必要としてしまいます。読込しながら自分のオブジェクトに変換していきたいところですから、定石どおりSAXを利用することにします。
SAXを利用する場合はNSXMLParserを使うか、libxmlを使うか、の二つの選択肢が標準的に用意されています。NSXMLParserは使いやすく、libxmlは高速である、との情報がありました。もちろん高速な方(libxml)を選択しますよ!

SAXはXMLの構文解析をしながら、適切なメソドを呼び出してくれますので、我々はイベントハンドラの登録と、イベントハンドラの実装を行います。

// タグを読み込んだら呼び出されます。
static void startElementHandler(void* ctx,
					const xmlChar* localname,
					const xmlChar* prefix,
					const xmlChar* URI,
					int nb_namespaces,
					const xmlChar** namespaces,
					int nb_attributes,
					int nb_defaulted,
					const xmlChar**attributes);

// タグが閉じられたら呼び出されます。
static void	endElementHandler(void* ctx,
					const xmlChar* localname,
					const xmlChar* prefix,
					const xmlChar* uri);

// 文字列を読み込んだら呼び出されます。
static void charactersFoundHandler(void* ctx, const xmlChar* ch, int len);

それぞれのハンドラではタグ名等に応じて独自形式のオブジェクトを作成し、設定していけば良いのですが、startElementHandlerでElementから属性値を取得するのがとても面倒です。速い方を選択した代償だと思って頑張りましょう!以下にその方法を抜粋して記述します。

	if (nb_attributes > 0) {
		NSMutableDictionary *attributes = [[[NSMutableDictionary alloc]init]autorelease];
		for (int i = 0; i < nb_attributes; i++) {
			NSString *key = [NSString stringWithCString:(const char*)charAttributes[0] encoding:NSUTF8StringEncoding];
			int length = charAttributes[4] - charAttributes[3];
			NSString *val = [[NSString alloc]initWithBytes:charAttributes[3] length:length encoding:NSUTF8StringEncoding];
			[attributes setObject:val forKey:key];
			charAttributes += 5;
		}
		// TODO: ここでオブジェクトに属性(attributes)をセットして下さい。
	}

MAGICナンバーも出てきますけど、最近はあんまり気を使わなくなりました。番号が直接書いてあるほうが良い場合もあるということにしましょう。

これで大抵のXML要素のパースが可能になりました。

|trackbacks(4) |22:03 2010/11/01

iPhoneシミュレータでは表示されるのに、実機にインストールすると画像が表示されない…。
そんなことが何度かありました。今回はUIImageViewでそんな現象に遭遇しました。
原因は不明(実機のイメージキャッシュかな?)ですが、以下の手順で正常に表示されるようになりました。

  1. 別の名前のイメージを指定
  2. ビルドと実行
  3. 実機で画像を確認
  4. アプリ終了
  5. 本来表示させたい画像を指定
  6. ビルドと実行
  7. 実機で確認=>OK!!

不思議なことに、これでちゃんと表示されるようになりました。

|trackbacks(2) |21:01

サーバとクライアント間の通信にはみなさんどのような方式を使われていますか?
これまで、サーバ側がApache+Tomcatでクライアント側がJavaApplicationなどというアプリケーションを開発してきたため、かなり自由な方式を試してきました。その中で今でも生き残っているのは、XMLの通信によるコマンドパターン実装です。
XMLによるコマンドを相互にやり取りすることで処理を進めていきます。サーバとクライアント実装を比較的独立して進めることができることも気に行っています。

ところが、このコマンドパターンで実装したシステムにiPhone/iPadの実装を追加しようとすると、ちょっと大変です。
まず、XMLのパースがちょっと面倒です。さらに、データをZIP圧縮して送受信しているため、ZIPのハンドリングをしなければならず、これまた面倒です。

徐々にではありますが、

  • iPhone/iPadにおけるXMLのパース
  • iPhone/iPadにおけるZIPデータの扱い

に関して記述していこうと思います。

|trackbacks(12) |14:39 2010/10/25

本日、AppStoreにてStone5のバージョンアップ版が承認されました。

日本語版だけで発生するバグの修正という内容だったのですが、「In Review」から「Ready for sale」まで結構長かったですね。約一週間掛ってます。
たぶん、ロボットに勝利するまでやったからだと思いますよ(笑)

みなさまも是非手強いロボットをぎゃふんと言わせて下さい!

|trackbacks(1) |17:21 2010/10/20

iPhone上で動くOpenGLを使ったボードゲームアプリの“>Stone5をリリースしています。
前回の更新で「対戦するロボットを変更して設定すると落ちる」というレビューを頂いていたのですが、現象がなかなか再現できずちょっと困っていたのですが、やっと原因がわかりました。

日本語版と英語版をリリースしているのですが、表示形式を多少調整するために、xibファイルを両方の言語で分けています。それがミスの原因で、英語版のOutlet接続は正しく変更したのに、日本語版のOutlet接続が間違っていました。AppStoreでは正しく動作するかどうかのチェックをしてくれているはずなのですが、今回は日本語版のみで発生するバグであったため、チェックを素通りしてしまったようです。

ご報告頂いたAppStoreレビュアーの方、ありがとうございました!

ただ今更新申請中ですので、承認された暁には是非ともアップデートして頂き、強いロボットと対戦して下さい!

追記(2010/10/13):
AppStoreヒマなのか、昨日提出したのに既に「In Review」になってます。

|trackbacks(0) |20:18 2010/10/12

統合開発環境になじめず、viでコードを書かないと気持ちが乗らないロートルです。iPhone/iPadのアプリケーション開発ですらviを使ってコードを書いています。UI部分のコーディングにはインターフェースビルダーを使わないといけないものだとばかり思っていましたが、インターフェースビルダーを全く使わないで開発できることが分って、ほとんどの開発がShell+viでできるようになりました。同士のためにその方法をまとめておきます。

  1. プロジェクト新規作成
    ここは仕方ないので、XCodeを使って普通にプロジェクトを新規作成します。
    プロジェクト名はSampleとしましょう。
  2. main.mの修正(ここ忘れやすい)
    元のコード
    int retVal = UIApplicationMain(argc, argv, nil, nil);

    変更後のコード
    int retVal = UIApplicationMain(argc, argv, nil, @”SampleAppDelegate”);

    これをしないといくらコードをいじっても画面が更新されずに途方にくれることに。

  3. info.plistの編集
    Keyが[Main nib file base name]のエントリを削除します。
  4. SampleAppDelegate.mの修正
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // 全画面サイズでウィンドウを作成します
        CGRect frameForWindow = [[UIScreen mainScreen] bounds];
        window = [[UIWindow alloc]initWithFrame:frameForWindow];
    
        // ここで必要な処理をします。
        // ビューコントローラーの作成やらなんやら。。。
    
        // ウィンドウを表示します。
        [window makeKeyAndVisible];
    }
    
  5. IBOutletを削除
    全ソース(*.m,*.h)からIBOutletを削除します。

これでIBとさよならできました!

後は自分で座標も色も何もかもゴリゴリとソースに書いていきます。万人にお勧め出来る方法ではないかもしれませんが、
インターフェースビルダーがらみのトラブルにうんざりした経験のある方は、IB無し開発を試してみてはいかがでしょうか?

|trackbacks(0) |03:20
ENTRY
  • UIBezierPathの描画で注意するべきこと
  • iPhone4でVGA出力
  • iPhoneアプリ審査落ち
  • OpenGLで省電力
  • iPhone/iPadアプリでのXMLパース
  • 実機で画像が表示されない
  • iPhone/iPadクライアントとサーバ間通信
  • バージョンアップ承認
  • アプリ更新
  • IBを使わない開発
  • CATEGORY
  • iPhone/iPad開発 (9)
  • Objective-C (2)
  • OpenGL (1)
  • その他 (1)
  • コラム (2)
  • 技術情報 (5)
  • 未分類 (2)
  • 製品情報 (2)
  • ARCHIVE
  • 2010年11月 (6)
  • 2010年10月 (5)
  • RECENT TRACKBACKS
  • 2011/7/12 OpenGLで省電力 « BridgeM...
  • 2011/6/21 今度TBXMLと速度比較し...
  • 2010/12/4 [iPhoneSDK] / UIBezierPathの...
  • 2010/12/2 アンチエイリアスが有...
  • 2010/11/28 iPhone/iPadアプリでのXML...

  • BM ON FACE BOOK
    Copyright © 2011 Bridge Metaware Co., Ltd. All Rights Reserved.