Hatena::Groupiphone-dev

hirogramの日記 このページをアンテナに追加 RSSフィード

2010-08-18手書きアプリのためのテストプログラム このエントリーを含むブックマーク このエントリーのブックマークコメント

実行した画面

手描きのアプリは、指の動きに追従してなめらかな線を書くのがなかなかに難しいものです。いろんなアプリが色々工夫していることかと思います。SpeedTextも工夫しています。んで、色々工夫していると、速くなったんだか遅くなったんだか自分ではよく分からなくなってきます。人間の感覚って難しい。

というわけで、手書き系アプリのための描画速度を測るかんたんなテスト用ビューを作ってみました。アプリの処理を変える前後でテストすると、速くなったかどうか分かりやすいかな、と。

実行すると、画像みたいな感じで「2秒間かけて丸を等速で12個描くような」指の動きをシュミレートします。1つの丸に60個の座標、計720個の座標を用意して、1つの座標の描画が終わるたびに、スタートからの経過時間に応じた座標を描画用のビューに渡します。(描画用のビューとは、あなたのアプリのビューです。なお、iPhoneSDKでは、本物のtouchなんとかメソッドを呼べないため、アプリ側に擬似的なtouchなんとかメソッドを用意する必要があります)

んで、touchなんとかを呼んだ回数をカウントして最後に表示します。呼べた回数が多いほどいいです。これは大雑把なスコアといえます。丸の形も見ましょう。touchに対する処理速度が偏っていると、丸が歪な形になります。あと、丸の上部がどれだけ閉じているかは、指のつけ離しに対する追従性を表します。一つの丸から次の丸に移るときにtouchEnd、touchStartを呼びますので、そこで時間がかかると、円の開始を描くのが遅くなり、上の部分が開いてしまいます。


使い方

1. この記事の最後に記したTestBaseViewクラスをプロジェクトに追加します。

2. テスト対象となるビューに、以下の3つのメソッドを追加します。locationに描画のための座標が入ってくるものとして、touchesBegan:withEvent等と同じ処理を記述してください。

- (void)touchesBegan:(CGPoint)location;
- (void)touchesMoved:(CGPoint)location;
- (void)touchesEnded:(CGPoint)location;

3. 以下のような感じでTestBaseViewを画面に追加します。(追加先はテスト対象ビューと異なってもよいです)

TestBaseView *testBaseView = [[TestBaseView alloc]
     initWithFrame:CGRectMake(0,0,320,100)];
[testBaseView autorelease];
[testBaseView setup];
[testBaseView setDrawView:drawView];     //このdrawViewを、アプリで使ってる描画用のビューにすること。
[self addSubview:testBaseView];    

TestBaseViewソース

テスト用なのでソース汚いです。すまんす。

#import <UIKit/UIKit.h>

#define TEST_NUMBERS_OF_POINT (10000)
#define TEST_NUMBERS_OF_DRAW_X (6)
#define TEST_NUMBERS_OF_DRAW_Y (2)
#define TEST_POINTS_IN_CIRCUL (60)
#define VIEW_WIDTH (320)
#define VIEW_HEIGHT (300)
#define CIRCUL_RADIUS (48)

#define TEST_FLAG_START (0)
#define TEST_FLAG_MOVE (1)
#define TEST_FLAG_END (2)

#define COUNT_SECOND (2.0)

@interface TestBaseView : UIView {
     UITextView *consol;
    
     CGPoint points[TEST_NUMBERS_OF_POINT];
     int pointFlags[TEST_NUMBERS_OF_POINT];
     int drawIndex[TEST_NUMBERS_OF_POINT];
     CGPoint pointOfEnd[1000];
     int countOfPoints;
     int countOfDraws;
     int pointIndex;
     int lastDrawIndex;
     BOOL isNextStart;
    
     id drawTestView;
     NSDate *startDate;
     int drawedPoints;
}
-(void)setup;
@end
#import "TestBaseView.h"

@implementation TestBaseView
-(void)drawPoint:(int)index {
     if (pointFlags[index]==TEST_FLAG_START) {
          [drawTestView touchesBegan:points[index]];
     }else if (pointFlags[index]==TEST_FLAG_MOVE) {
          [drawTestView touchesMoved:points[index]];
     }if (pointFlags[index]==TEST_FLAG_END) {
          [drawTestView touchesEnded:points[index]];
     }
}
-(void)endOfDraw {
     consol.text = [NSString stringWithFormat:@"points:%d",drawedPoints];
}
-(void)drawNext {
     double t = -[startDate timeIntervalSinceNow]; //double型で秒を返す(マイナス)
     drawedPoints ++;
    
     //COUNT_SECOND秒間でcountOfPointsまで描画するから、
     int index = t*countOfPoints/(double)COUNT_SECOND;
     if (index > countOfPoints-1) {
          if (isNextStart==NO) {
               //終了
               [drawTestView touchesEnded:pointOfEnd[lastDrawIndex]];
               [self endOfDraw];
          }
          return;
     }
    
     int dIndex = drawIndex[index];
     if (lastDrawIndex<dIndex) {
          //次の図になったので、前の図を終了
          if (isNextStart==NO) {
               [drawTestView touchesEnded:pointOfEnd[lastDrawIndex]];
               isNextStart=YES;
          }else{
               //次の図の開始
               [drawTestView touchesBegan:points[index]];
               isNextStart = NO;
               lastDrawIndex = dIndex;
          }
     }else {
          [drawTestView touchesMoved:points[index]];
     }
    
     [NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(drawNext) userInfo:nil repeats:NO];
}
-(void)start:(id)sender {
     NSLog(@"start");
     pointIndex = 0;
     isNextStart = YES;
     lastDrawIndex = 0;
     drawedPoints =0;
     [startDate release];
     startDate = [NSDate date];
     [startDate retain];
    
     [drawTestView touchesBegan:points[0]];
    
     [self drawNext];
}
-(void)dealloc {
     [startDate release];
     [consol release];
     [super dealloc];
}
-(void)setup {
     UIButton *startButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
     startButton.frame = CGRectMake(10, 30, 100, 30);
     [startButton setTitle:@"start" forState:UIControlStateNormal];
     [startButton addTarget:self action:@selector(start:) forControlEvents:UIControlEventTouchUpInside];
     [self addSubview:startButton];
    
     consol = [[UITextView alloc]initWithFrame:CGRectMake(0,60,320,40)];
     consol.opaque = YES;
     consol.backgroundColor = [UIColor whiteColor];
     consol.text = @"hoge";
     consol.alpha =0.5;
     consol.userInteractionEnabled = NO;
     [self addSubview:consol];
    
     // point のセットアップ 丸を格子状に並べて描画する
     int index = 0;
     int dIndex = 0;
     CGFloat radius = 48;
     CGFloat addX =(VIEW_WIDTH-(radius*2)-10)/TEST_NUMBERS_OF_DRAW_X;
     CGFloat addY =(VIEW_HEIGHT-(radius*2)-10)/TEST_NUMBERS_OF_DRAW_Y;
     for (int drawY=0;drawY<TEST_NUMBERS_OF_DRAW_Y;drawY++) {
          for (int drawX=0;drawX<TEST_NUMBERS_OF_DRAW_X;drawX++) {
               CGFloat startX = drawX * addX + radius+10;
               CGFloat startY = drawY * addY + radius+10;
              
               for (int i=0;i<TEST_POINTS_IN_CIRCUL ;i++) {
                    CGFloat x = startX-sin(2*M_PI* i/TEST_POINTS_IN_CIRCUL)*radius;
                    CGFloat y = startY-cos(2*M_PI* i/TEST_POINTS_IN_CIRCUL)*radius;
                    points[index] = CGPointMake(x, y);
                    drawIndex[index] = dIndex;
                    pointFlags[index] = TEST_FLAG_MOVE;//move
                    if (i==0) {
                         pointFlags[index]=TEST_FLAG_START;//start
                    }else if (i==TEST_POINTS_IN_CIRCUL-1) {
                         pointFlags[index]=TEST_FLAG_END;//end
                         pointOfEnd[dIndex] = CGPointMake(x, y);
                    }
                    index ++;
               }
               dIndex++;
          }
     }
     countOfPoints = index;
     countOfDraws =dIndex;
    
}
-(void)setDrawView:(id)view {
     drawTestView = view;
}
@end

VIEW_WIDTH、VIEW_HEIGHTは対象となるビューのサイズです。大きくすると、大きなビューを想定して丸の間隔が広がります。

ソースのCOUNT_SECONDは、シュミレートする時間(秒)です。ここを減らすと、もっとシビアな条件を測定できます(実際のSpeedTextのテスト時は1秒にしてます。画像は2秒のもの)

このテストプログラムでは、全体的に遅くても安定した速度で処理されると、いい結果になるので、描画自体の厳密な速度は測れないんですけどね。あと、touchが呼ばれる部分をスキップしちゃってるし。まあ、安定した速度で書けるかというテストですね。

hirogramhirogram2010/08/18 09:53TestBaseViewの-(void)drawPoint:(int)index と、メンバ変数pointFlagsへの代入処理は、不要でした。あっても動きますが、邪魔なら削ってください。

2010-02-27

Evernoteの海外イベントについてブログ書いた

06:35 | Evernoteの海外イベントについてブログ書いた - hirogramの日記 を含むブックマーク はてなブックマーク - Evernoteの海外イベントについてブログ書いた - hirogramの日記 Evernoteの海外イベントについてブログ書いた - hirogramの日記 のブックマークコメント

はてなの日記の方に、Evernoteのイベントについてブログ書きました。

これって、自動でリンクとかできないのかしら。はてなグループの使い方が未だによく分かりません。


2010-02-26 Evernoteの海外イベントに出ました

http://d.hatena.ne.jp/hirogram/20100226


おうちに帰ってブログ書くまでがイベントよね。

まだ帰ってませんけれども。

RaynesRaynes2016/05/07 18:51A million thanks for posting this inarimftoon.

2009-09-23OS2.2.1のデバイスでも動くけどOS3.0なら専用の機能が動くアプリを作る このエントリーを含むブックマーク このエントリーのブックマークコメント

表題の通り、OS2.2.1のデバイスでも動くけどOS3.0なら専用の機能が動くアプリの作り方です。ADCにサンプルコードがあるのでご存じのかたも多いと思いますが、私は最近知ってありがたかったので、まあ報告します。

OS3.0特有の機能というとメールに画像が添付できたり、コピペが使えたりとかです。他にもあった気がします。OS3.1も出ちゃってるのでいろいろあることでしょう。


やりかたは、ADCのサンプルコード"MailComposer"のReadMe.txtに丁寧に書いてあります。


やるのは割と簡単ですが、注意すべき点を先に挙げておいたほうがいいようです。

  • OS2.2.1のデバイスでOS3.0用の処理を通らないように、ソースを分岐する必要があります。分岐しないとアプリが異常終了します。なお、OS3.0の処理をソースに書いている時点でOS2.2.1のビルドはエラーになります。したがって、コンパイラに頼らず自分でチェックする必要があります。やっかいです。
  • 同様にOS3.0以降のデバイスでOS2.2.1専用の機能(あったっけ?)を通らないように注意する必要があります。こちらはOS3.0でビルドすればわかるはずなので問題ないかと思います。
  • アプリを申請に出すときに、構成を間違えないように注意する必要があります。デバイス3.0とかでビルドしちゃって、リリースされてから気づくなんてことのないように(書いてて自分が心配になってきた)。

このようにソースコードが煩雑になり、ミスも誘発しやすくなりで、開発者にとってはいいことはありません。新しくアプリを作る場合は素直にOS3.1用で作った方がいいです。OS2.2.1でアプリリリースしちゃってて、この後どうしようかという人向けですね。私みたいに。


最後に手順を書きます。MailComposerのReadMe.txtも読みましょう。

これはすべての構成(Distributionも!)に対して行って、3回くらいチェックしてください。

そうすると、XCodeのウィンドウ左上の構成とかを選ぶドロップボックスに「ベースSDKを使用」というのが現れます。これがどっちでも動くよ版です。

f:id:hirogram:20090923220353p:image

  • 3. メールのようにOS3.0独自のフレームワークを使う場合は、フレームワークをプロジェクトに含めた上で、役割(?)をWeakに変更します。リンクの仕方がWeak Linkという奴になるようですね。XCodeのフォルダツリーでターゲットを選ぶと右画面で変更できます。

f:id:hirogram:20090923220355p:image

  • 4. 処理を切り分けます。MailComposerではOS3.0用のクラスが存在するかどうかで切り分けていますね。私はこんな感じで、問い合わせをするメソッドを用意しました。
-(id) init
{
	[super init];
	isOs30 = NO;
	Class pasteClass = (NSClassFromString(@"UIPasteboard"));
	if (pasteClass != nil)
	{ 
		isOs30 = YES;
	}
	
	return self;
}

-(BOOL)isOs30 {
	return isOs30;
}

以上です。MailComposerのReadMe.txtも熟読しましょう。

リジェクトされないか気になるところですが、今申請中なので通ったら報告します。サンプルコードがあるくらいなので大丈夫だと思いますが。。

kimadakimada2009/09/24 20:41なるほど、これが正しいやり方なんですね。このサンプルは見ましたが、ReadMe.txtは、あまり読んでませんでした。。。

私の場合は、とりあえず、NSInvocationで動的に3.0のAPIを呼び出す方法で解決しました。

http://d.hatena.ne.jp/kimada/20090811/1249970669

複雑なことをやる場合には、まったく不向きな方法ですね。ちゃんとReadMe.txtを読むべきでした。。。
バッテリー残量の取得は、2.xで非公開APIを使ったものが出回っていたこともあり、「それを使ってないよね?」というAppleから確認の電話が来ました。そこで事情を説明したところ、その翌日にリリースされました。
なので、2.xでビルドしたアプリから、3.0のAPIを呼び出すこと自体は、問題ないと私は解釈しています。

hirogramさんのアプリも、無事に審査が通ることをお祈りしております!

hirogramhirogram2009/09/24 22:02コメントありがとうございます。
なるほど、動的にやる方法もあるんですね。勉強になります。
動的にやると、OS2.0でビルドしてもビルドが失敗しない(他の部分のエラーチェックができる)のはメリットですね。
iPhoneの場合、どのやり方が正しいというか、リジェクトされなかったものが正しいみたいな感じがありますね。
いろいろなやり方で試してみましょう。

hirogramhirogram2009/10/05 00:55報告すると言って忘れてました。
無事審査通りました!

2009-06-08

有料トップアプリ1位御礼

22:23 | 有料トップアプリ1位御礼 - hirogramの日記 を含むブックマーク はてなブックマーク - 有料トップアプリ1位御礼 - hirogramの日記 有料トップアプリ1位御礼 - hirogramの日記 のブックマークコメント

SpeedTextが有料トップアプリケーションのNo.1を獲得しました!

応援してくださった皆さんありがとうございます。

で、今回ちょっといいことがわかりました。

それは、「小さなツールでしかも有料でも、ゲームアプリと勝負できるんだ」ということです。

言うまでもなくゲームは人気を取りやすいし売れるし、上位の物は私も持ってたりするんですが、

手の込んだ重量級アプリには勝てないとなっちゃうと、アプリ作るのもつまらんですよね。

まあ数時間後のWWDC以降、アプリの順位は大きく様変わりし、1位はつかの間のこととなるのは容易に予想がつきます。

それでも、ここまでこれたのは、私にとって結構な収穫でした。

もちろん、このアプリもまだまだがんばりますけどね!

MiracleMiracle2016/05/07 18:44TYVM you've solved all my prebloms

TassilynTassilyn2016/05/08 22:36After Launching Dolphin Browser HD, please click <a href="http://ollykumh.com">Me;;B>u-ookmarks->nQuick</a> Access->Bookmarks. Then holding on the bookmark you want to delete/edit will come out a menu, choose “Delete/Edit Bookmark”. Everything is done!

2009-06-07アプリ第2弾リリースとアプリサイズの削減方法

iPhoneアプリサイズの削減方法

10:41 | iPhoneアプリサイズの削減方法 - hirogramの日記 を含むブックマーク はてなブックマーク - iPhoneアプリサイズの削減方法 - hirogramの日記 iPhoneアプリサイズの削減方法 - hirogramの日記 のブックマークコメント

今回開発している上で気付いたアプリのサイズの削減方法を2点挙げます。アプリのサイズが大きいと起動時間に影響が出るので、私は結構気にしたりします。もう常識だったらごめんね。

  • プロジェクト情報のビルドタグGCCオプションからGenerate Debug Symbolsのチェックを外すと、実行モジュールのサイズが劇的に削減される。デフォルトではReleaseもチェック付きなので、これを外す。もちろんDistributionも。 http://iphone-dev.g.hatena.ne.jp/moira/20090228(moiraさんの日記)にあるように、GCCオプションはアクティブSDKでDeviceを選択しているときしか表示されないみたいなので注意。
  • Objective-Cモジュール毎のサイズは、buildフォルダ配下の**.buildというフォルダの下をたどって行くと、*.oファイルがあるのでこれでだいたいわかる。 ちなみに、メソッド一つにつき(内容がたとえ1行でも).oファイルは3〜4KB大きくなる。メソッドを頑張って削ると実行モジュールのサイズも小さくなる。

ではでは。

LinaLina2011/05/14 10:59Kudos to you! I hadn't thoghut of that!

dkxypjnvgzbdkxypjnvgzb2011/05/14 22:31ywcpdB <a href="http://icadilnkhomr.com/">icadilnkhomr</a>

viwblfmviwblfm2011/05/15 22:032tCxwH , [url=http://nuwfrnuziydm.com/]nuwfrnuziydm[/url], [link=http://erjgmspazgjx.com/]erjgmspazgjx[/link], http://qhrbgemrzpth.com/

ivfwplbunivfwplbun2011/05/17 13:05yMcSTv <a href="http://tpkghnumpcij.com/">tpkghnumpcij</a>

ulxrwefulxrwef2011/05/29 23:08NWOye3 , [url=http://jbovfwgmxgjy.com/]jbovfwgmxgjy[/url], [link=http://bsadnhvmkvsw.com/]bsadnhvmkvsw[/link], http://gpurbjeptytj.com/

LekanLekan2013/10/14 15:06Thniikng like that shows an expert at work

MichaelMichael2013/10/15 04:14Me dull. You smart. That's just what I <a href="http://ydgchqfz.com">needde.</a>

ShivaShiva2013/10/15 15:51I watend to spend a minute to thank you for this. http://eotzkemw.com [url=http://zelbcgc.com]zelbcgc[/url] [link=http://wniuqjod.com]wniuqjod[/link]

ElbaElba2013/11/03 18:28<a href="http://qwcqzlyxvr.com">Haaaahhh.</a> I'm not too bright today. Great post!

EdjaEdja2013/11/12 23:35It's like you're on a <a href="http://zrluickb.com">miosisn</a> to save me time and money!

SantiagoSantiago2013/11/14 12:06I waetnd to spend a minute to thank you for this. http://phogackoh.com [url=http://xdonotic.com]xdonotic[/url] [link=http://getosjf.com]getosjf[/link]

SteeStee2013/11/16 03:25Posts like this <a href="http://johjxcp.com">briegthn</a> up my day. Thanks for taking the time.

KanjanaKanjana2013/11/18 02:54Thinking like that is really impvrssiee http://jqxnybiolt.com [url=http://wuazlqvvb.com]wuazlqvvb[/url] [link=http://wvjwelqogzq.com]wvjwelqogzq[/link]