HMDT Blog | ページ 32

iCloudセミナーやります


MOSAで、iCloudのセミナーやります。「iOS開発セミナー:iCloudの理論と実装」。内容的には、先日やりましたMSM2011のリピートセミナー。それに参加できなかった方向けですね。若干のブラッシュアップはあり。

開催日は2月の8にち。iCloudのまとまった情報って、いまのところどこからも出てないから、興味のある方は是非。

NewYear, New YouとAppスターターキット


App Storeに、「New Year, New You」というのが追加されていた。新しい年の新しい自分のために選ぶアプリ、っていう意味かな。体のメンテナンス、心のケア、お財布管理、時間のカテゴリでアプリがオススメされている。

HMDT開発ものでは、お財布管理としてMoneyTronがピックアップ。

また、Appスターターキットってのもある。こっちは初めてiPhoneやiPadを買った人にオススメのアプリ、ってことかな。こっちには、MoneyTronデジタル大辞泉が選出。

選ばれれば、嬉しいです。どちらもよろしく。

追記:

New Year, New You」で、iMandalArt HDも選ばれておりました!見逃してしまった。すまん。

UIColorに便利なDeveloper Color Picker


社員の人から教えてもらった話。

PanicがDeveloper Color PickerっていうcolorPickerファイルを配布している。~/Library/ColorPickersの下にインストールすると、標準のカラーピッカーにタブが追加される。「Developer」という名称が付いているように、開発者向けのピッカー。開発者向け?

何をやってくれるかというと、選択した色のためのUIColorやNSColorのインスタンスを作成するためのソースコードをクリップボードにコピーしてくれる。こんな感じで。

[UIColor colorWithWhite:0.855 alpha:1.000]

コードのテンプレートも、色々な種類が用意されている。

いままでは標準のカラーピッカーで色を見つけて、それを255で割って、それでソースコード書いていたけど、これを使うと楽になりそう。

StreetScrollerで無限スクロール


iOSのUIScrollViewで、無限スクロールがやりたかった。フリックしてもフリックしても、どこまでもスクロールできる、ってやつ。

そのためにまず思いついたのは、contentOffsetをとっても広く取ること。でもこれだといつかは端にたどりついてしまうので、却下。次に思いついたのは、UIScrollViewのdelegateを設定して、scrollViewDidScroll:メソッドあたりで、contentOffsetが一定のところまでいったら逆の端に戻してやる、というやり方。これはやってみて、それっぽくはなったんだけど、contentOffsetを戻すところでスクロールが一瞬止まってしまう。残念、却下。

となると、後は自前のクラスを作って対応するしかないのかなー、でもUIScrollViewのあの手触り感とか減衰とかバウンスとか再現すんのは難しいなー、と思ってネットを探していたら、そのものずばりのサンプルがAppleから公開されていた。

それが、StreetScroller。ダウンロードして動かしてみると、おぉっできるぞ!確かに無限スクロールしているぞ!

ソースコードを見てみた。基本的な考え方は、contentOffsetを戻すやり方と変わらないみたいだ。ポイントは、UIScrollViewのサブクラスを作る事。そしてlayoutSuviewsをオーバーライドして、その中でcontentOffsetの処理を行うこと。これだとスクロールを止める事なくcontentOffsetを変更できるようだ。なるほどー。

これ、2011のWWDCで紹介されたネタらしいね。そっかー、やっぱりWWDC行かないとだめだね。

直感的に速い処理、遅い処理


プログラミングをしていると、この処理は速くできるなとか、この処理は時間がかかるはず、というのが直感的に分かるようになってくる。これはきっと時間のかかる処理になっちゃうんだろうな、という箇所にさしかかってくると、指がイヤイヤをするようになる。この、他の人に説明しても分かってもらえないような感覚は、多くのプログラマが持っていると思う。

で、何が速くて何が遅いかってのは、プラットフォームによって異なる。例によってうちの得意なのはiOSなので、iPhoneで速い処理、遅い処理を、ぱっと思いつくものを並べてみよう。

  • ネットワーク処理。これは遅いね。どうにもならないほど絶望的に遅い。えー、ネットワークは最近充分に速いじゃない、と思っているそこのあなた。コンピュータの中の世界は基本的にミリ秒の世界だ。1秒もかかるようだったら、それは絶望的な遅さだ。例えるならば、ローカルファイルにアクセスするのとネットワークファイルにアクセスするのは、電話で話をするのと郵便で話をするくらいに違う。「もしもし」と書いて郵便を送る。「はいはい」と返事が郵便で来る。「元気?」と書いて郵便を送る。「ボチボチだね」と返事が郵便で来る。ネットワークアクセスってのはこのくらいのスピード感だな。

    遅いからダメなのではなく、遅いからそれに見合ったプログラミングをする必要がある。非同期にするとか、プログレスインディケータを回すとか、キャンセルボタンを用意するとか。

  • ファイルアクセス。これは速い。特にiPhoneやiPadは、Macに比べれば全体的に非力なマシンなんだけど、ファイルアクセスは充分に速い。これが遅い場合は、ファイルを一度に読み込んでメモリに展開して使い回すとかの技が使うんだけど、そんなものは必要ないくらい。これはHDDじゃなくてフラッシュを使っているのが大きく貢献していると思われる。
  • グラフィックス処理。これは遅かったり速かったり。どこで分かれるかというとGPUを利用できるかどうかにかかっている。たとえば、オフスクリーンでUIImageを作るとする。ビットマップコンテキストを作って、そこに描画して、UIImageに変換。これは時間がかかる。フルスクリーンの画像を作ると0.5秒くらいかかってしまう。でもこれを一度画面に表示してやって、拡大縮小や回転を行うと、これは速い。画像はQuartz内部でOpenGLのテクスチャに変換されるんで、GPUの恩恵を受けられる。だから画面に表示されるまで少し我慢してもらえば、後はサクサク動かせる。
  • 画像処理。これもGPUの影響が大。もしビットマップを1ピクセルずつ変更するような画像処理を、ソースコードを連ねてCPUでやろうとしたら、えらい時間がかかる。でも、Core ImageやAccelerateフレームワークといった適切なものを使えば、チョッ速になる。自分で書くな、フレームワークに任せろ、ってことだ。
  • テキスト処理。エンコーディングの変換とかXMLパースとか。以外に遅い。これは純粋に整数演算になるんで、CPUの処理速度に依存する。だからiPhone 4Sなら速いけど、iPhone 3Gとか持ってこられると遅くなる。どの機種に合わせて書くか、ってことが重要になる。

他にもフォント周りとか、データベース周りとか、動作速度を気にするところはたくさんある。この辺りでも、経験を積むとどうすれば速くなってどうすると遅くなるのかが分かってくる。パッと見て重いかなという処理があっても、GPUやフレームワークを上手に使うと直感よりも速くできるときもある。自分の思い込みが修正されて、直感力が上がってくると楽しいね。

Cocoaのバグ?そんなものはあり得ない


アプリの完成を目指してガシガシとプログラミングをしているとき。順調に進んでるなーと思ってたら、なんてないところでバグにつまずくことがある。小さなバグなら無視して他のところやっちゃうんだけど、たまにこれを解決しないとどこも進める事ができないよ、ってのが出てくる。

関係しそうなソースコードを、ここかなあそこかなと、ためつすがめつ検討しても、原因が分からない。こんなところで時間とられている場合じゃないのに、早く他の箇所の実装にとりかからないといけないのに、と気持ちばかりが焦る。

こんなときにしばしば導きだされる結論は、「これはCocoaのバグだな!」というもの。「だってどう考えたってこのAPIを呼び出すと動きがおかしくなるんだよ」と。いやいや、それはあり得ない。自信を持って断言するけど、ほぼ確実にあり得ない。

「Cocoaのバグだな!」と言い出したとき、結論は次の3つのどれかになる。

  1. 自分のバグでした。ごめんなさい。
  2. APIの使い方を間違っていました。または、適切な使い方じゃありませんでした。
  3. ほんとにバグだったよ!

いままでの経験からいうと、98%くらいは1.ですな。残りは2.。3.は見た事ないい。特に経験のあるプログラマほどこの罠に陥りやすい。これ絶対Cocoaのバグだよ、これだからAppleは信用できないよ、MacもiPhoneも不安定だよ、とどなりちらす人のところに行って、どれどれとソースコードを見てみると、えーっとこの変数って初期化されてないんじゃない?とかいうのが、サクっと見つかったりする。

これは別にその人が不注意だ、という話じゃない。自分がバグを埋め込む可能性と、Cocoaにバグがある可能性を比べてみよう、ってことだ。たったいま自分が書き上げたに過ぎないものと、過去十数年に渡って何十万人というプログラマの目にさらされてきたものがあったとき、どっちを信用する?そりゃ後者だよね。

ソースコードにとって大切なものは、経験値だ。どんなに名前の通った人や会社が作ったものでも、新しいものは弱い。リリースしてユーザの手に触れて、バージョンアップを繰り返す事でのみ、強くなる。経験値を積んだソースコードこそが財産だ。

えっと結論としては、Cocoaを信用して自分を疑おうよということと、自分たちのソースコードも経験を積ませて強くしようよ、ってことかな。

新年のごあいさつ


あけましておめでとうございます。今年もよろしくお願いします。

新年のあいさつといいつつ、ちょっと去年のことを振り返りますと。去年のHMDTは、人の出入りの激しい年でした。辞める人がいたり。入ってくる人がいたり。最終的には人数も増えたし、メンツも良くなったんで、いい体制になりましたよ。

そのおかげで、今年はいいチャレンジができるんではないかと。チャレンジは、うちの強みが活かせることでやりたいね。他にはない、うちだけの強み。それは何かと言われれば、まぁ面白くもなんともない答えだけど、蓄積してきた知識と技術ってことになるね。それと、人への継承かな。

トレンドを見据えつつも、それを無視するようなことをやっていきたいね。ソーシャルソーシャル言っている連中をあざ笑うような感じで。知識は人の中にある。人が大事なんです。それをつなぐシステムなんざ、どうだっていいんです。

ACAccountStoreのcompletionHandlerはサブスレッドっぽい


iOS 5から、システム側にTwitterアカウントを登録できるようになった。このアカウントは、Accountフレームワークを使って取得できる。その手順は、ACAccountStoreをインスタンス化して、requestAccessToAccountsWithType:withCompletionHandler:を呼ぶ。取得できると、指定したブロックが呼ばれるので、その中で処理を行う。

コード書いてテストしていたら、このブロックはメインスレッドではなくてサブスレッドで呼ばれるようだ。マジすか。ドキュメントにそんなこと書いてねーじゃん。従って、ここからユーザインタフェース周りを触ると、訳分からない挙動になる。すごい罠だ。

App Store Rewind 2011のHMDT


今年もこの季節がやってきた。ということで、App Store Rewind 2011が発表された。

開発者としては自分の作ったアプリをまず探す。今年はHMDTに関係するものは、5つ入ってた。去年が8つだったから、少し控えめになったかな。

入ったアプリのうち公表しても構わないものは、まずデジタル大辞泉

ランダムハウス英和辞典

そしてMapFan for iPhone東北特別版

大辞泉とMapFanはずーっとアップデートし続けているものなので、こういったものが評価されると嬉しいね。iOSアプリでも、長期に渡って使い続けてもらい、開発も続けることができるんです。

UIGestureRecognizerはけっこう鬼門


iOS 3.2以降、つまりiPad登場以降に付け加えられた、UIGestureRecognzierというクラスがある。iPhoneやiPadのタッチパネルを操作する際の、いろんなジェスチャーを認識してくれるものだ。タップ、ピンチ、回転、スワイプ、パン、長押しなんかを認識してくれる。このクラスの登場前は自前で判断ルーチンを作らなくてはいけなかったので、かなり便利だ。

最近になって、Cocoa標準のクラスでこのジェスチャーをバリバリ使うものが出てきた。これがけっこう鬼門でねぇ。苦しんでる。

たとえば、UIPageViewController。ページ表示を行ってくれる便利クラス。このクラスは、ページめくりっぽい操作を提供するために、タップ、スワイプ、パンに対するUIGestureRecognizerを使っている。このクラスだけを使っているうちは、まぁいいんだけど。

UIGestureRecognzierの便利でありやっかいな点は、ビューの階層構造を無視するところ。UIPageViewContorllerで管理するビューの上に、ボタンを置いたとする。すると、スワイプやパンといったジェスチャーは、ボタンをすり抜けてUIPageViewControllerまで届く。うむ。これは便利だ。しかし、スライダーを置いたときも、同様にすり抜けていく。これにより、スライダーを動かしながらページもめくれてしまう、という事態が発生する。これは困るぜ。

または、ページを表示しているときに、シングルタップでメニューを表示したいとする。ページの左右両端タップではページ移動、それ以外をタップしたときはメニューのトグル、っていう電子書籍アプリによくある操作を実現したい場合ね。この場合、左右両端タップはUIPageViewControllerのジェスチャーが管理する。それ以外のタップは、自前のクラスのジェスチャーで管理する。ということで、2つのジェスチャーの競合を管理しなくてはいけない。めんどくさい。

いまのところきれいな解決策が見当たらないので、ケースバイケースで対応している。これだと、新しいユーザインタフェース追加するたびに、ジェスチャーにすり抜けていかないか、競合しないか、ってことを気にしないといけない。うーん、すっきりしない。