iPhoneの最近のブログ記事

Animating UIViewのエントリーではUIViewにラップされたインターフェイスからCore Animationの機能、アニメーションをさせてみた。簡単なお約束ごとでアニメーションを実行できるのだけど、Core Animationのクラス、CALayerだとどうだろうか。

いきなり結論から言ってしまうと、CALayerを使うともっと簡単にアニメーションができてしまう。実はCALayerクラスのアニメーション可能となっているプロパティに値を設定すると、それは即時実行ではなく現在値からのアニメーションとして設定される。

つまり何も考えずにプロパティ値を設定するだけでアニメーションを実行できてしまうわけだ。これをCoreAnimationではImplicit Animationと呼んでいる。

たとえば、

theLayer.alpha = 0.0f;
とするだけで、レイヤーはalpha=0へと消えていく。

今回はImplicit Animationを使ってみようと思う。

Animating UIViewのエントリーでUIViewにラッパーされたCoreAnimationを使ってみたのだけど、今回はもう一歩CoreAnimationの世界に踏み込んでみる。とはいっても、アニメーションさせようっていうわけでなく、CoreAnimationで用意されている機能を使ってちょっとおいしいところをつまんでみようかということなのだ。

CoreAnimationはOSXではLeopardで追加された機能の一つなのだけど、iPhoneOS(おっとiOS)では最初から使える機能だ。ただ、CocoaとCocoa touchの類似性を保つためなのか、そのViewとの関係性は同じように実装されている(何となく後付け的な感じがうかがえる)。

UIViewに対応してそのCoreAnimationレイヤーであるのがCALayerクラスだ。layerプロパティがUIViewに用意されている。ちょっとわかりにくいのが、UIViewとしてもヒエラルキーを組めるのだけど、それとは別にCALayer側でも親子構造が組めるということだ。

今回扱うのはこのCALayerクラスだ。いくつかプロパティを持っているのだけど、注目するのは形状に関するプロパティだ。

OSXのLeopardからCoreAnimationというフレームワークが追加された。それによってCoverFlowなんかを実現している。それまでは空間的な管理しか行わなかったGUIシステムにおいて、時間の管理もOSが面倒を見てくれるようになったというのが、CoreAnimationのキモなのではないかと思う。

そして、OSX系の流れをくむiPhoneOSにもCoreAnimationは含まれている。iPhoneOSはOSXの紆余曲折のまだ後の方に出たということもあり、構造的にはモバイルOSにしてはかなりモダンな、OSXの成功も失敗も踏まえた上で設計されていると感じることがある。

さて、iPhoneのCoreAnimationだけど、かなりお手軽に使う方法が用意されている。ダイアログをビヨヨンとだしたり、スライドしてカットインさせたり、はたまた二つのViewをクロスディゾルブさせたり。UIViewControllerのトランジション効果なんかにもプリセットのアニメーションパターンが用意されているのだけど、簡単なお約束でアニメーションさせることが出来るので使わない手はない。

今回デモ用にEscapeButtonというジョークソフトを軽く組んでみた(ほんとに数行しか書いてない)。名前からして出落ちな感もあるけど、実装を見つつご紹介しようと思う。

もうすでにAppStoreにならんでるのだけど、とある方面からのリクエストにより、ほとんどの方にはいまいち使い道がないのではないかと思われるアプリを実装した。どういったツールなのかというと、同時に複数ターゲット(最大16)に対してPingのステータスをとり続けられるというツールなのだ。

ネットワークの回線を生業とするプロの方々が使うツールらしい。

例えばネットワーク回線が集中するようなイベント会場などでどのルートがどれぐらい負荷がかかってるかなどをチェックして、対策を打つなんて事に使うようだ。

実装はICMPのEchoプロトコルを使って実装している。つまり、普通のPingなんだけど、iPhone OSではネイティブソケットでICMPタイプを作らせてくれないので、そのあたりの実装が一工夫必要だった。しかし、それもなんとか解決できた。

他にも同時にPingを投げるにあたって、構造上別ターゲットのものに影響をうけないように、といったことにはかなり気を配って実装してある。見た目は地味だけどプロの方がつかえるツールとして仕上がってるのではないかと思う。

そして、このエントリのアプリケーションイメージを作るのにiPhone Screentakerというソフトを使用したのだけど、スクリーンショット画面をごらんの通り、iPhoneの画像にはめ込んでくれる。他にも何通りか用意されていて、なかなか良い感じになる。おすすめです。

PingmaniaはRusty-raven社よりAppStoreで発売中です。

Irodoriの1.1版は嬉しいことにUSのitunes storeのNew and noteworthyに載せてもらうことができた。1.1版の特徴は、要望が多かった既にPhotoAlbumに保存してある画像からの解析機能なんだけど、これを実装するときに、わたしとしては初めて同じバージョンのiPhone OSのデバイスの機種間での挙動の違いを体験したので、メモとして書いておこうと思う。

iPhone OSは基本的なアーキテクチャは一貫している印象があって、iPhoneかiPod touchか、OpenGLES2対応かそうでないか、ARM6か7ぐらいかの違いしか無くて、しかも後方互換性があるので、一番ベーシックなところで作っておけばどれでも特に対策をする必要もなく問題なく動くというものだと思っていた。

特に一番基本的なApplication FrameworkであるCocoa touchなんかは上位レイヤーにいるのでどのデバイス用でも同じものを使ってると(そうしない理由があまり浮かばないので)思っていたのだ。

もちろんシミュレータは今までにも違う挙動を示すことがあった。しかし、iPhoneで開発をした方なら分かると思うのだけど、まあ、シミュレータだしな、というところはあった。

さて、問題になったのはUIScrollViewだ。このクラスは表示サイズより大きいものや、複数あるビューを選ぶようなとき、スクロールや拡大縮小機能を提供してくれる。UITableViewはUIScrollViewの派生クラスだ。こういう前置きも必要無いぐらい基本的なクラスだと思う。

このクラスには、中においたコンテンツビューの端に余白を空けるように出来る機能がある。それがcontentInsetで、それぞれに指定したピクセル分端に余白が出来る。コーディングとしては同じ事がUIScrollViewを小さく作っておいてclipsToBoundsをNOにしておくことでも実現できる(clipsToBoundsをNOにするとコンテンツビューがそのサイズでクリップされなくなるので)。

contentInsetを使った方が便利な点はスケールした場合も座標の計算を行わなくても良いという点。コンテンツビューのスケールに依らず指定ピクセル分の余白を空けてくれる。もちろん、スケールに合わせてコンテンツビューサイズを変更すれば同じ事は出来る。

Irodoriでは指定された画像から解析用の画像を切り出すという処理の切り出し部分を指定するところにUIScrollViewを使用した。初期値は縦または横の短い方がちょうど切り出す領域の大きさになるように拡大または縮小している。切り出し領域は画面端よりオフセットされた位置にあり、その上下左右をcontentInsetで指定している。

このスケールされた状態で領域と同じ大きさの場合スクロールはされない。contentInsetの分とスケールされた辺の長さを足したものが丁度UIScrollViewの大きさと同じになるためだ。正方形の場合は固定された状態に(初期的に)なる。

これが期待されるべき動作で、仕様通りでもある。さらにいうとiPhone 3Gの3.1.3ではその通りに動作した。しかしシミュレータでは動作が異なっていた。拡大縮小およびスクロールを繰り返した後、または最初から。そのタイミングは決まったものではなく、突然「外れる」のだ。まさしく、外れると表現するのがいちばんその状態にしっくりと来る。

シミュレータだけの問題なら放っておいても問題ないのだけど、iPod touch 1st gen.で試してみたら、なんとシミュレータと同じ挙動になったのだ(つまり、「外れた」)。バージョンも確かめてみたのだけど3.1.3だった。

つまりは同じバージョンのOS間でAPIの挙動が異なったというわけだ。

こういう時はたいてい非正規な初期化など、どこかミスをしてることが多い。しかし、色々と試してみたけれども、片方はちゃんと動作し続け、もう片方は「外れた」ままだった。

そのものずばりな解決方法があるのかもしれないが、わたしはとりあえず次のように対処しておいた。

  • UIScorollViewDelegate protocolのscrollViewDidEndDragging:willDecelerate:のdecelerateがNOのとき
  • またはscrollViewDidEndDecelerating:が呼ばれたとき
このときにcontentOffsetの値の値が範囲を超えていた場合に範囲内に戻すようにした。contentOffsetプロパティに直接設定しても良いし(setContentOffset:)、setContentOffset:animated:を使用し、戻るところをアニメーションさせることも出来る。アニメーションさせた場合も終了時にDelegateのメソッドscrollViewDidScroll:が呼ばれるので、そこでスクロール中は禁止していた処理を許可状態などにする。

もっともこれが確認できるのは一部の機種に限られるのだけど。

Irodoriの場合、領域切り出し部分なので、仕様通りの動作を期待すると「外れていた」場合、領域外までふくむことになり、最悪の場合BAD_ACCESSで落ちてしまう(そして落ちた)。UIが絡むところはやはりその値がちゃんと想定した範囲内かどうかはチェックした方が良いな、と、再認識したのだった。

申請していたアプリが、今日審査に通ったという通知が届きました。これが前から少し話題に出していたアプリで、カテゴリとしてはカメラアプリになるのだけど、写真を撮る事が目的ではなく、カメラを通してそこにある色をサンプリングしようというのがそのコンセプトです。

アプリケーションの名前は"Irodori"といいます。

使い方は至って簡単で、他のアプリと同じようにツールバー上のカメラアイコンを押すとカメラ画面になります。

ここで撮影をすると、それを解析した特徴色が16色ほどピックアップされるので、その中から気に入った色があればお気に入りマークをつければ、自分のカラーパレットにお気に入りの色が集まっていくという仕組みです。

そうやってピックアップした色見本をメールやtwitpicで家族や友人に見せることも出来ます。

無料のお試し版は出来ることはここまでで、保存できる枚数にも制限があるのですが、アプリ内課金で機能制限解除版を購入していただくと、さらにパレットをAdobe act形式やase形式、PaintShop pal形式でのエクスポートも可能になります。もちろん保存できる枚数の上限も大幅に増えます。

基本機能は無料お試し版で使用可能なので、是非一度お試しください。

再申請したアプリの結果は、今日の時点ではまだ返ってきていない。大体in reviewになってから結果がくるまでに営業日で7日ぐらいかかるようだ。アプリの審査が通ったら、お披露目しようと思うのだけど、また要再提出となると、また一週間ということになって・・・。iPhoneアプリはこのあたりが一番難しいですね。

任天堂やソニーなんかはもっと速いんだけど、審査をする本数も全然違うというのもあるんだろう。そういえば任天堂にはマリオクラブ(いつのまにか会社になっててびっくりした)というのがあり、初めて名前を聞いたときは秘密結社?などと思ったのだけど、ソフトのクォリティコントロールをしているところだ。ここが、OKを出さないとリリースさせてもらえない。ソフトウェア上のバグから、どのロットのハードではちゃんと動かないなどというレポートまで報告してくれる。どのロットのハードでもちゃんと動かないとダメというのが、任天堂は遊べるということには強いこだわりがある会社なんだなという印象をうけた思い出がある。

さて、今回申請したアプリはたくさんの画像を扱うもので、すべてをメモリ上に持っておくことが出来ないので、必要になったらロードしないといけない。とはいえ、いちいち待たされてから、画像の内容を判断するのはもどかしいので、まずは荒くでも見たい。最初に軽いけど荒い画像を表示しておいて、そのうちに隙を見て正式な画像をロードする、つまり遅延読み込み(delayed loading)だ。

Appleは昔から、アプリケーションの挙動はこの場合はこうするのが良いという「お作法」をHuman Interface Guidelines(HIG)という形でアプリケーションデベロッパに提示している。そのせいもあってか、Macのアプリはこういうものはここにあるとか、こうすればいいということにカンがかなり効きやすくなっている。

それは、iPhone OSでも同じで、iPhone Human Interface Guidelinesという形で示されている。

先日、iPhoneアプリをsubmitしたのだけど、昨日HIGに適合しない部分があるというrejectをいただいてしまった。その結果のメールを受け取ってから、しまったと思ったのだけど、動作がちゃんと行われるというのは事前にチェックしていたのだけど、HIG関連はチェックしていなかった。これからは必ず申請前のチェックに入れようと思う。また、チェックリストも作ろうかなと思っているところだ。

わたしが引っかかったのはHIGでもSystem-Provided Buttons and Iconsという項目。そのなかに"Standard Buttons for Use in Toolbars and Navigation Bars"という項があるのだけど、つまり、システムデフォルトで用意されているアイコンには決まった動作が規定されていて、そのアイコンを使うならその規定に従ってねって事なのだ。

わたしは"Action"というボタンアイコンを押したときに独自ダイアログを出すように実装していた。規定の項目を見ると"Opens an action sheet that allows users to take an application-specific action"とある。アクションシート(UIActionSheet)を開いてその中から動作をユーザに選ばせるというのが規定されている動作だ。その点が違うので修正してねって事だった。

早速アイコンを独自のものに変えて再提出した。事前によく読んでおけば避けられたポカミスってところかな。ついでに表示上の自分のURLのスペルを間違うという恥ずかしいミスを修正できたのでラッキーだったと思ったりもする。

と、いうわけでiPhoneアプリを作るデベロッパーにとっても、HIGに目を通しておくっていうのは重要じゃないかと思うのだ。

Locole!

| | コメント(0)

わたしが音楽を担当させてもらったiPhone用のパズルゲームが本日発売になった。

線路パネルをうまくつないでいって電車をゴールに導くという、ルールはとてもシンプルだ。ただ解く(ゴールに到達する)だけならそんなに難しくはないだろう。ゲームとしてはイージーな部類に入るので、歯ごたえを求める方には物足りなく感じるかもしれない。

しかし、それを上回る魅力がこのゲームにはあると私は感じる。ミニチュア感というのだろうか、箱庭的なそのグラフィックが、まさに見ているだけで楽しいのだ。デバッグしながら本気で遊んでしまったゲームというのはかなり久しぶりな気がする。

フィールドには鉄橋やトンネルもある。そこを通す必要が無くてもなんとなく通したくなる(そしてはまったりもする)。画面上には乗車率ゲージがあるのだけど、それが赤になった状態で電車をあちこちに連れて行くと、なんとなく申し訳ないような気がしてくる。そういうイマジネーションがかき立てられるミニチュア感がそこにあるのだ。

リプレーモードもついていて、時計代わりに出来たりもするのだけど、なぜか思わず見入ってしまう。時間泥棒である。

カタルシスなどとは無縁な、とてものほほんとしたゲームだけど、基本1−3面がお試し無料なので、ぜひプレーしてみてください。私的に超プッシュです。

Music from LocoleもWorksのページに追加しました。よければ聴いてみてください。

XcodeのヘルプでiPhone SDK 3.1のドキュメントを見ようとすると「ファイルが見つかりませんでした」なるエラーダイアログが出るのだけど、目的のドキュメントは表示されるという不思議な状態になっていた。必要な情報は3.0のドキュメントでも得られるので放置していたのだけど、ついに3.1のドキュメントでないとダメという状況になり、何か探す度に出るダイアログに辟易して、ようやく抜本的に解決しようと思い立った。

この現象は多分メジャーなことだと思われるので、日本語でずばり検索すれば出てくるだろうと思ったのだけど、出てこなかった。情報がないと言うことではなく、もうちょっと探し方を工夫すれば出てきたのだと思う。

日本語がダメなら英語で・・・とおもったのだけど、はて、このエラーは英語版ではどう出てるのだろうかと色々思案したあげく、"xcode 3.1 docset"で検索してAllenさんのblogのエントリーにたどり着くことが出来た。

あとは、氏のエントリーの通り作業をすればいいのだけど、また後々同じような症状になったときのヒントになればと、手順を書いておこうと思う。

  • XcodeのドキュメントセットからiPhone OS3.1をアンサブスクライブする。
  • Xcodeを終了し、3.1のdocsetを削除する。
    標準では/Developer/Platform/iPhoneOS.platform/Developer/Documentation/DocSetsにインストールされている。
  • 古いバージョンのドキュメントを取得する。方法は以下のようにwgetなどで。
    wget http://devimages.apple.com/docsets/Oct2009/com.apple.adc.documentation.AppleiPhone3_1.iPhoneLibrary.xar
    
  • ダウンロードしたアーカイブを解凍して、docsetを先ほどのディレクトリにコピーする。

    以上で終了だ。