パスワード入力欄をブルブルする

iOS用アプリでパスワード入力UIを作ってるのですが、無効なパスワードを入力した時のフィードバックをどうしようか考えて、Mac OSX Lionのログイン画面のように、パスワード入力フィールドが「イヤイヤ」って感じで左右に揺れる感じにしようと思いました。いっそこれくらいCocoaの標準メソッドとしてあってくれても良さそうなものでしたが、UITextfieldのリファレンスを見る限りはなさそうだったので自分で実装してみました。さして高度なことしてるワケでもないですし、あんまりエレガントなソースでないかも知れないですが晒しておきます。もっとこうすりゃいいんじゃね?的なコメントも歓迎。

2011.10.27追記:

s1tnkさんにアドバイスいただいて大幅な簡略化に成功したので、更新版を貼ります。

//パスワードが不適切だった場合に入力欄を揺らす
-(void)shakePasscodeField {

    [UIView setAnimationRepeatAutoreverses:TRUE]; //最初の位置に戻る
    [UIView animateWithDuration:.05
         animations:^(void) {
             passcode.center = CGPointMake(passcode.center.x – 10, passcode.center.y);
         }
         completion:^(BOOL finished) {
             [UIView animateWithDuration:.05 animations:^(void) {
                  passcode.center = CGPointMake(passcode.center.x + 10, passcode.center.y);                                             
                  }
                  completion:^(BOOL finished) {
                      [UIView animateWithDuration:.05 animations:^(void) {
                           passcode.center = CGPointMake(passcode.center.x – 10, passcode.center.y);
                           }
                           completion:^(BOOL finish) {
                               [UIView animateWithDuration:.05 animations:^(void) {
                                    passcode.center = CGPointMake(passcode.center.x + 10, passcode.center.y);
                                    }];
                           }];
                  }];
         }];

1メソッドで完結できたのでほとんど説明は不要だと思います。passcodeというのがテキスト欄の名前です。

旧バージョンとの違いは、

  • setAnimationRpeatAutoreversesの存在を教わり、左に行って戻る、右に行って戻るの2フェーズで表現できた
  • completion引数に次の処理をブロックで丸ごと角ことでアニメーションを連鎖記述できるようになった
  • 結果として2フェーズx2回を1つのメソッドに完結させ、状態変数を一切なくせた
  • durationは往復なので時間を倍の0.05にした

という辺りです。振動回数のカスタマイズはやりにくくなっちゃいましたが。

 

実際の動作はこんな感じ(IE9かiOSのSafari位しかインラインで再生できないかも)。

動画がインラインで再生されない人は、こちらからMP4をダウンロードして再生して下さい(44KB)。

■以下旧バージョン

前提として、.hファイル当たりで、

IBOutlet UITextField *passcode;
INT gakuburuCounter;
BOOL isFirstLoopForShakePasscodeField;

という3つのオブジェクト、変数を宣言してあるとします。

んで、.mファイルでメソッドを2つ。

//パスワードが不適切だった場合に入力欄を揺らす
-(void)shakePasscodeField {

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDuration:.1];     
    [UIView setAnimationDidStopSelector:@selector(shakePasscodeFieldLoop)];
    switch (gakuburuCounter % 3) {
        case 0:
            //左へ動くフェーズ 
            [UIView setAnimationDuration:.025];     
            passcode.center = CGPointMake(passcode.center.x -10, passcode.center.y);
            break;
        case 1:
            //左位置から右へ動くフェーズ 
            [UIView setAnimationDuration:.05];     
            passcode.center = CGPointMake(passcode.center.x +20, passcode.center.y);
            break;
        case 2:
            //右位置から初期位置へ戻るフェーズ 
            [UIView setAnimationDuration:.025];     
            passcode.center = CGPointMake(pa
sscode.center.x -10, passcode.center.y);
            break;
        default: 
            break;
    }
    [UIView commitAnimations];
   
}

-(void)shakePasscodeFieldLoop { 
    if (isFirstLoopForShakePasscodeField == TRUE) {
        gakuburuCounter = -1;
        isFirstLoopForShakePasscodeField = FALSE;
    }

    if (gakuburuCounter < 5) {
        gakuburuCounter++;
        [self shakePasscodeField];
    }
}

こんな感じ。

#つーか、そろそろコードをカラーリングしてくれるライブラリを導入した方がいいんだろうなぁ…

パスワードを検証してNGだったら

isFirstLoopForShakePasscodeField = TRUE;
[self shakePasscodeFieldLoop]

って感じで呼びます。

簡単に補足しておくと、テキストフィールドが定位置から左に10ピクセル、右に20ピクセル、左に10ピクセルと移動するのを1つのセットとします。ただしこれを単純に連続して呼ぶと、前のアニメーションが終わらないうちに次が実行されてしまい、正しく移動してくれないので、1つのアニメーションが終わる度に次のステップのアニメーションを実行する仕組みが必要でした。そこでそれを管理するメタメソッド(そんな言葉あるのか?)としてshakePasscodeFieldLoopを作りました。isFirstLoopForShakePasscodeFieldフラグがTRUEの状態で呼ばれると、ループカウンタgakuburuCounterをリセット(ここでは-1)して、フラグをFALSEにします。そしてgakuburuCounterをカウントアップしながらshakePasscodeFieldを呼び出します。呼ばれたshakePasscodeFieldではgakuburuCounterを3で割った答えを使って順に3つの動作パターンを実行し、アニメーションが完了した後でshakePasscodeFieldLoopを呼びます。このルートで呼ばれたshakePasscodeFieldLoopはisFirstLoopForShakePasscodeFieldがFALSEなのでカウンターはリセットせず、カウントアップだけして再度isFirstLoopForShakePasscodeを呼びます。これで、gakuburuCounterが-1~5にカウントアップする過程で、各フェーズが順に2ループ実行されます。

カスタマイズですが、-10とか20ってのが移動ピクセル数です。左に10、右に20、左に10って感じで辻褄を合わせます。つまり、振幅を倍にするなら、-20、40、-20とかするワケです。

 

shakePasscodeFieldLoop内の5を8にするとブルブルが3回になります。以降3を足すと1セット増加です。

shakePasscodeField内のUIView setAnimationDurationの値がブルブルの速度です。case 1のところは移動距離が倍なので所用時間も倍にしておくのがポイントです。

Xcodeで幽霊.xibに困った時の覚え書き

Xcodeで開発をしていて、あるタイミングからInterface Builderから.xibファイルに対して行った変更がビルドに反映されなくなってしまいました。

  • Clean
  • Clean Build Folder (Option押しながらClean)
  • シミュレーター上のアプリを削除
  • Xcodeの再起動
  • OSの再起動

なども効果無し。挙げ句、Xcode上から当該.xibファイルを削除(他フォルダに移動)してもビルドしてくれやがります。Xcode上でもFinder上にも存在しないゴーストがどこかに残ってる!

結果として解決したのは、海外の掲示板stack overflowのこのエントリの一番下(記事執筆時)のコメント。よりによってusefulカウンタが0(笑)。そろそろσ(^^)もIDとって評価記入するようにしないとなぁ。

で、具体的にはXcodeのもってるキャッシュを削除。その場所は、

/Users/(ユーザ名)/Library/Developer/Xcode/DerivedData/

ここに今までビルドしたプロジェクト毎のフォルダがあるので、それを丸ごと削除。Lionだとユーザのホーム下のLibraryは不可視になってるので、ターミナルを使うが良いでしょう。

どうもここのキャッシュはXcode上で元ファイルが消されても消されずに使われてしまうっぽいです。では元々何故起きたかについてですが、多分、.xibをローカライズして、実体ファイルがen.lprojとja.lprojに移動/コピーされた時の参照が正しく書き換わらなかったっぽい気がしています。なんかやり方が悪かったんですかね?これによってXcode上では実体ファイルである各言語別のファイルを更新し続けたものの、ビルドには親フォルダにある(あった)ファイルのキャッシュが使われ続けてしまった、ということではないかと思っています。

同日追記:

@s1tnkさんより、Xcode4から同じことをする方法を教わりました。こっちの方が簡単そげ。この作業自体はエラーのハイライティングが壊れた時とかにもする一般的なものみたいです。特定プロジェクトがなんとなく調子悪いぜって時のお試し作業の1つとして覚えておくと良さそうです。

  1. Organizerを開く
  2. 目的のプロジェクトを選択する
  3. Delived Dataという見出しの右にある「Delete…」をクリック

 

delete_derivedData

iPhone4S無事ゲット

また今年もサーバートラブルで大変だったiPhone4Sですがなんとか入手できました。ヨドバシの朝イチ枠(8:00~9:00AM)で入店し、カウンターに1組目で座ったものの機種変更登録のサーバーが輻輳でダウン。結局予約と一緒にペーパーベースの処理に切換。機種変更なので端末は渡してもらえ、microSIMの差し替えとアクティベーションをすれば普通に使える形。機種変更登録はおそらく端末盗難時の管理用にユーザにシリアルを紐づけておきたいとかいう運用面のニーズでやってることなんでしょうね。そっちはサーバーが復帰次第お店がやっといてくれるという感じで。microSIMじゃない人(つまりiPhone4からの機種変以外の人)はSIMの切換ができないので、持ち帰っても電話としては使えなかったみたいです。

結局受け取って店を出たのは10時。カウンターに座れたので店員さんと雑談したりして時間をつぶしてました。

■ハード面

外観はマナースイッチの位置が若干かわった以外違いはなし。お気に入りのパワーサポートのAirジャケットは4S対応版待ちですが、無理矢理入れれば一応入りました。若干膨らむもののスイッチ切換も可能。

当然フィルムは4用がそのまま使えます。2chで話題になっていたマイクロソリューションの「漆黒」を買ってみたんですが、ボケがパワサポよりもひどい印象で速攻処分。結局4用で買ったパワサポアンチグレアが2枚組で1枚余ってたので利用。

レスポンスは明らかにサクサク感が増しています。特にiOS5になってフリック入力の遅延が顕著になっていたのが解消した感じ。あとiPhone4で最大の不満だったカメラ起動の遅さが改善。iPad2並になりました。

通信速度は下り14.4Mbpsに対応しても今のところ体感では違いを認識できないですね。対応エリアにいかないと。

最大の不満は液晶です。明らかに黄色い(色温度が低い)です。iPhone4もホワイトモデルが出た頃からこの色味のパーツに変わってしまっていたので嫌な予感がしてたんですが、やはりか…という感じ。見慣れれば気にならなくなるのかなぁ。(可能かどうかわかりませんが)4のものと交換してしまいたい衝動に駆られますw。

■ソフト面

iPhone4Sならではってところはあまりないです。強いて言えばSiri位ですか。日本語は来年に対応予定だそうです。キーボードにマイクボタンがついてて、一般的な文字入力欄にディクテーション入力ができちゃいます。

■カメラ画質

IMG_20111014_162720

まだ近所で適当に数枚撮っただけですが、レンズの明るさは実感できます。室内で撮った時に顕著です。部屋が汚いんでサンプルは屋外のものでw。タイルの質感とかイイカンジです。ちなみにLED、HDRはオフです。

ただ等倍でみるとちょっとノイジーかなーという印象。TwitterやInstagramに上げる分には、レスポンス向上も相まって実用度はアップしてますね。コンデジの出番はますます減りそう。

欲を言えばそろそろRAW保存できるようになってくれないかなと。


 

液晶の黄色さには凹みますが、総じて乗り換えて良かったと思っています。割賦残金が免除される3G/3GSな人はもちろん、カメラや3Dゲームを多用するなら4からも乗り換える価値が充分にあるんじゃないでしょうか。

WALKMAN買い換え A865へ

ちょうど2年使ったWALKMANのA845の2世代後のモデル(先代はマイナーチェンジだったけど)、A865をポイントでゲットしてみました。

このシリーズのデジタルノイズキャンセル(以下NC)は逸品で、電車乗る時や賑やかなカフェ、ファミレス等で作業する時の必需品でした。A865ではその特徴を受け継ぎつつ、

  • 更なる高音質か(デジタルアンプがS-Master MXへアップグレード)
  • 全面フルタッチUIに
  • Bluetooth対応
  • 有機ELから液晶に変更(ダウン?)
  • 若干大型化

という変化を遂げました。Bluetooth好きなσ(^^)ですが、本機に限ってはNCを活用してナンボなのであまり興味なし。使用頻度も月に数回もない程度なので見送るつもりだったんですが、現物を触ったらうっかり…

■ハード面

若干短くなり、横幅がそれなりに増えてる感じ。厚みも増してるかな?感覚としては一回り大きい印象です。ただネックストラップをつけて胸ポケットに入れて使うのが主なσ(^^)の利用スタイルではそう致命的な差ではないかなと思います。

液晶は大型化していてジャケット絵も大きく見えるのは良いです(ただiTunesから移した曲の場合、表示できない場合があるのも相変わらずなのでガッカリ感も大きいorz)。若干色温度が高いというか少し黄色っぽいのが残念。

タッチパネル化してもサイドにしっかり音量+/-、次曲、再生/ポーズ、前曲の5ボタンが用意されてあるあたりはさすがSONY。ブラインドでも操作しやすいです。

HOLDボタンはタッチとサイドキーの両方を無効化するか、タッチのみにするか設定で選べます。サイドボタンはさして誤反応のリスクはないので後者の方が便利な気がします。タッチはやはり誤反応があって、胸ポケットの中で何度か勝手に曲が遷移したりしたので、ホールド状態にしておくのが吉かなぁ。ただスイッチ自体はさほどON/OFFしやすくないです(かなり小さなスライドスイッチ)。HOMEボタンの2連続クリックで解除とかもう少し簡単にON/OFFできると良かったかなと。というか画面スリープみたいなことができないのがいけない気がしますね。HOMEのアイコンに一発スリープボタンがあって、それで画面消してる間はHOMEボタン以外は藩王しない、くらいで良かった気がします。

A845の時に後から発売になったショートケーブル+延長ケーブルのイヤフォンも結局標準添付はされず、付属は長いものです。ネックストラップ派は追加出費を覚悟しておいた方がいいかも知れません(旧機種用がそのまま使えます)。確かに接点が増えると音質には悪い影響しか出ないですが、そもそもそのレベルで音質云々言う人は標準添付のイヤフォンなんか使わないと思うんですよね…

■ソフト面

前面にはHOMEボタンがあり、第一階層はアイコン、その下はリストをスワイプでスクロールして選択という、まぁざっくりいうとiPod touchっぽい操作体系になりましたw。レスポンスはかなりサクサクです。ただスクロールのつもりが指を離す時に選択までされてしまうことがたまにあります。もう少しチューニングの余地がある感じ。

操作性で最も不満だった、NCのモード設定(電車とか飛行機とか)がなぜかホーム画面のNCアイコンを選んだところから変更できず、初期設定の中から、というちぐはぐな点も修正されていました。NCの設定がすべて一画面で網羅されています。

■音質

例によってたいした耳ではないので参考程度ですが、「びっくりする程ではないけど、でも良くなってる気がする」という感じでしょうか。高音の解像感もあがってる気がするし、低音も嫌みのないでもしっかりとした安定化のある鳴り方をしてる気がします。「BOSEっぽい」というと怒られるかも知れないですがw、丸い感じの低音です。女性ボーカルもしっとりしてる気がします。まー、A845に具体的な不満があった訳じゃないので、劣化してなきゃOKってとこです。

ただ、おースゲーって感激する曲とそうでもないなってのがあります。ソース音源の音質差なんでしょうかね。ちなみに基本256kbpsのAAC(iTunesで変換)です。ロスレスはiTunesとx-アプリで互換性がないので使ってないです。

ネットではホワイトノイズが格段に減ったという評価が多いみたいですね。σ(^^)はもともとそんなに気になってなかったのでわかりません。

dgKeyframe2Chapterをリリースしました

かなり前の「iOS向け高機能MP4自炊まとめ」というエントリで、Pegasys社のTMPGEncシリーズで書き出された.keyframeファイルを、mp4chap.exeでmp4ファイルに埋め込んで、iOS端末等でチャプターとして利用できる.chapters.txt形式に変換するツールを作った、と書いたところ、1年も経ったところで公開リクエストをいただいたので、公開しました。

こちらに置いておきます。

例によって自分用にサクッと作ったモノなので、あまり汎用性はないかも知れませんが。

また秒単位以下までキッチリ出力してほしいという要望があったので、v1.2では選択できるようにしてみました。もともと秒単位以下を切り捨ててた理由は、フレーム単位で指定してもmp4のようなフォーマットでは精密にジャンプできないことが多く、大抵少し前後してしまうことを鑑みて、例えばオープニングを飛ばした時に、少し本編の頭が欠けるよりはオープニングのお尻がちょろっと見える方がマシだろうと考え、フレーム単位は切り捨てをしていた、という経緯があります。が、まぁその辺りはお好みなのでなるべく厳密に計算した値を入れられるようにもしてみました。σ(^^)はMediaCoderでエンコすることが多いですが、今だとTMPGEnc Mastering Work 5でエンコすればKeyframeがきっちりIフレームとして扱われる気がするので、ドンピシャの方がいいのかも知れませんね。

ちょっと計算式がこれであってるか自信ないのでどなたかチェックしていただけると助かります。簡単には、.keyframeファイルの数値を29.97で割ると整数部分が秒単位になるので、それを取り除いた小数点以下の部分を使い、(特に指定してないですが多分)小数点以下4桁目を四捨五入して上位3桁を使用しているつもりです。

#そういう意味では「秒単位で丸める」というチェックボックスのラベルは不適切だなぁ(実際は切り捨て)。機会があれば直します。

なお、BDInfo.exeの「View Report…」等から取得できるBDMVのチャプター書式を.txt拡張子で保存したファイルをドロップした場合は、元々フレーム単位まできっちり出力してたみたいなので、こちらはそのままです。というか「秒単位で丸める」がONでも丸められません。手抜きですみません…

あと保存時にカチャっと確認音がしてたんですが、これもON/OFFできるようにと要望があったので対応しました。

 

ともあれ同好の士のお役に立てば幸いです。