UIGestureRecognizerが糞使えない理由

皆使ってる UIGestureRecognizer ですが、こいつで泣かされる人もわりと多いと思う。


UIGestureRecognizerについては、ググってくれればいい。
UIGestureRecognizerの派生クラスで以下のものがある。


UITapGestureRecognizer タップ
UIPinchGestureRecognizer ピンチインアウト主に拡大縮小
UIPanGestureRecognizer ドラッグ
UISwipeGestureRecognizer ページめくりやスクロール等のスワイプ
UIRotationGestureRecognizer 指2本で回転させる感じ
UILongPressGestureRecognizer 長押し


いわゆる、1~4本指スワイプ、2本指回転、長押しあたりを検出するクラスである。
こいつがほぼ使えない。


なぜかというと、touches{Began|Moved|Ended}との相性がとても悪い。
Gesture系のイベントが発生すると、touch系のイベントが発生しない。


これによって、touchesMovedを検出したいのに、swipeGestureが検出されるということが起こる。
あるいは、swipeGestureを検出したいのに、touchesBeganが発生するというようなことが起こる。
また、swipeGestureやLongPressGestureから、touchEndedへつなげるといったようなことができない。


例えば、単なる長押しならいいが、長押しのあとにスライドを検出したい場合や、
回転の後に、指離しを検出してなにかしたいという場合は、
UIGestureRecognizerでやろうとすると、複雑な実装になる。


つまり、回転、スワイプなどは、結局自前で作ってdelegateして使うということが一番簡単なので、
簡単なビューで即席的なものならありだが、それ以外の場面では、これらのクラスは極力使わないようにしたい。
touches{Began|Moved|Ended}だけでタッチ処理を実装するのが、今のところ一番いいと思う。

ResponderChainとDelegate

UIKitでプログラミングしていると、サブビュー(UIViewとその派生)が次々と増えていく。


ビューが重なりあった状態では、最も下層にあるビューが、FirstResponderとなる。
FirstResponderというのは、最初にイベントを受け取るオブジェクトのこと。
例えば、TextFieldにフォーカスがあってたら、TextFieldがFirstResponderである。


で、指でViewに対してタッチすると、touches{Began|Moved|Ended}の一連のイベントが発生するが、
このイベントというのは、FirstResponderがまず受け取る。
FirstResponderにてイベントハンドラが定義されている場合、実行される。
イベントハンドラが定義されていなければ、NextResponderがFirstResponderになる。
UIViewの場合は、その親ビューにイベントが渡される。
このように、次々とスーパービューへとイベントが渡されていく。
これをResponderChainという。


FirstResponderにイベントハンドラがあるが、
その親ビューや、そのさらに親ビューのイベントハンドラや関数を実行したい場合は
Delegateを使う。


Delegateは大体の場合が、非公式プロトコルというObj-Cの仕組みで実装する。
Javaでいうところの、Interfaceのような感じ。


コンパイル通るかわからないけど、簡単な例を示すと、だいたい次のような感じ。
View1が、View2の親ビュー。
View2でタッチしたイベントを、View1にdelegateする。


というわけで、はてな様、私にMac11インチくださったら、役立てますので宜しくお願いします。

touchDelegate.h

@protocol touchDelegate
   - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
@end

View1.m

#import "touchDelegate.h"
@interface View1:UIViewControler <touchDelegate>
{
   UILabel *label;
}
@end

@implementation View1
- (void) viewDidLoad
{
   UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100,100)];
   view2.delegate = self;
   [self.view addSubView:view2];
}
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
   label.text = @"aho";
}
@end

View2.m

#import "touchDelegate.h"
@interface View2:UIViewController <touchDelegate>
{
   id delegate;
}
@end
@property (nonatomic,retain)id delegate;

@implementation View2
@synthesize delegate;
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
   [delegate touchesBegan:touches withEvent:event];
}
@end

非公開ソースのインタフェースの数を調べる

ソースが公開されていないライブラリ、オブジェクトファイル(*a,*o)の呼び出されているAPI数を調べる。
次のスクリプトを実行させると、dにAPIの一覧がのる。

#!/bin/bash
#呼び出し側のソース:
find ${caller_path} -name "*.[oa]" | xargs nm | xargs cat > a
grep "U " a > aa
sort aa |xargs uniq > aaa #未解決シンボル一覧
cut -f 3- < aaa > aaaa #シンボル名だけ抜き出す

#呼び出され側ソース:
find ${callee_path} -name "*.[oa]" | xargs nm | xargs cat > b
grep -v "U " b > bb
sort bb | xargs uniq > bbb #解決シンボル一覧
cut -f 3- < bbb > bbbb #シンボル名だけ抜き出す

cat aaaa bbbb > c #呼び出し側未解決シンボル、呼び出され側解決シンボルをつなげる
sort cc | xargs uniq -u > ccc #解決されたシンボルは消える

diff -c aaaa ccc | xargs grep "+ " > d #解決されたシンボルの一覧をdに出力する

Android(環境構築)

APR/1にXperiaをゲットし、今週月曜の会社の飲み会で、先輩に、
「そういうの買った人はAndroidのアプリを自作するでしょ」
とさらっと云われたので、密かに家で作るか。


ま、そんなのはどうでもいいことで、いつも通りメモ。


環境:
MacOS X(10.5.8)
JDK(1.5.0_20)
Eclipse(3.4.2)
Android SDK(1.6)
Android Development Toolkit(0.9.6v20)(Eclipseプラグイン)
google API(?)


上記は、ここからゲット:
http://developer.android.com/sdk/index.html


bashrcに下記追加:
JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home
ANDROID_HOME=/Developer/android-sdk-mac_86-r4
PATH=$PATH:${ANDROID_HOME}/tools



まず、AndroidのシミュレータAVDを生成。
この引数のtargetは、googleSDKのIDに対応。
$ android create avd --target 2 --name aho1


Hello World までは以下のサイトが参考になった。
http://d.hatena.ne.jp/ynakajima/20090522

一人の開発の意識

一人で開発して、納期に間に合わせるために必要だと思うのは以下のこと。


・リソース
自分自身の全ての生きる時間をリソースとして考える。
生活のどれがリソースに対しどの程度のコストを払うかを考える。
あらかじめ、配分を決めておき、そこから大きく乖離するような配分にしない。
スケジュール、いつまでにどれを明確にする。


・優先順位
一人で開発し、期限がある以上、全部を実装することはできず、どれかは必ず捨てることになる。
機能やタスクは全て書き出して把握する。
機能やタスクの全てに優先順位があり、取捨選択の判断が必要。
まず最初に優先することは、最低限の動作。


・UIや機能は使い勝手良くシンプルにする。
多くの機能を盛り込むとバグがそれだけ増え、自分自身に跳ね返ってくる。
複雑で高コストな機能に着手するときは、効果がそれだけあるのかよく考え、
代替え手段などを一通り見比べ切り捨てることも必要。
複雑で高コストな機能は、一見便利だが、骨折り損なことが多いのでほとんど捨てることになる。

「イケメン人狼タウン」リリースしました

1ヶ月くらい、OpenSocialをぼちぼちとやってましたが、

昨日、「イケメン人狼タウン」というmixiアプリをリリースしました。
http://mixi.jp/view_appli.pl?id=9624

まだまだテスト段階ですが、遊んでくださる方を大絶賛募集しています。

忙しい方のために3日で進行する村と、通常の1日進行村の2つがあります。