2010-12-21

Inflectorのやっていることがイマイチわからなかったのでまとめてみました

どだい日本人には複数形なんて...って話の前に、その他のメソッドの動作も理解できていなかったのでコードを追ってみました。以下メモ。読んだのはCakePHP 1.3.6のInfratorです。

pluralize
singularize
1. 最後の単語が例外単語帳にマッチしたらそれを返す
2. 単語全体が変更なしグループにマッチしたら何もせずに返す
3. ルールを一つずつ当てはめていき、マッチしたら実行して返す

まあ、この二つは想像通りというか、パターンは複雑だけどやっていることは単純明快。

humanize
1. 全ての"_"をスペースに
2. 各単語の最初の文字を大文字、それ以外を小文字に変換

camelize
1. humanize
2. スペースを取り除く

underscore
1. 先頭文字を除き、文字列中の大文字の前に"_"を挿入する
2. 全部小文字に

これがくせ者。大文字が続く場合に、各文字の前に"_"が入ります。
例)PostgreSQL => postgre_s_q_l

またこの正規表現が、戻り読み言明を使っていて最初読めなかったです。
/(?<=\w)([A-Z])/ まだまだ勉強不足ですな。

tableize
1. underscore
2. pluralize

classify
1. singularize
2. camelize

variable
1. underscore
2. camelize
3. 先頭の文字を小文字に

slug
1. アルファベットレターと数字以外の文字を" "に変換
2. 連続する" "を"_"に変換
3. 先頭と最後に"_"が一つ以上あった場合は取り除く

これも正規表現を読むのに苦労しました
/[^\s\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu

Unicode 文字プロパティ参照

おそらく結局
/[^\s\p{L}\p{Nd}]/mu
と一緒なのではと思うんですが、どうなんでしょう。

2010-12-16

PHPで簡単にコンソールにカラライズした出力をする方法



Lithiumの表示が綺麗だったので、その部分だけ簡単に使えるように抜き出してみました。PHPの変態的ともいえる配列の動作(辞書的+数字のミックス)を取り入れたんで、比較的使いやすくできました。以下のような感じで、緑色の"world"が表示されます。

console_out(array('Hello', 'green' => '"world"', '!'));
echo "\n";

array() が余計かなぁ。ここがもっと簡単にかけるとうれしいんだけど。こんな風にかけたらうれしいな。

console_out(['Hello', 'green'=>'"world"', '!']);
echo "\n";

2010-10-16

Lithium FAQの一部を翻訳してみたよ

LithiumのFAQが素晴らしかったので翻訳してみました。口調が適当だなぁ。ですますがいりまじってます。翻訳は自分の語り口とはまた変わってくるので面倒なり。


さて、内容は静的なクラスやメソッドとテストのしやすさを例に、プログラミングにおける重要な概念を説明しています。Lithiumのかかげる「consistency」を垣間見れる内容。


分らスタティックをあちこちで使ってるね。テストするのがすごく大変なんじゃないの?

厳密に言って、スタティックなものは実に簡単にテストできるよ。 フレームワークだけでなく、その上のアプリケーションも含めて、全体をテスト可能なコードにしておけるように、Lithiumは関数プログラミングからいくつかのコンセプトを借りてきているんだ。 これらのコンセプトを理解するために、まずいくつかの用語を定義しておこう:

状態 :ソフトウェアを書くうえで必要不可欠なもの。ウィキペディアは状態を "システムの様々な条件を計測した値のスナップショット"と定義しているPHPアプリケーションの開発においては、文脈、もしくはスコープにによって異なるが、Webサーバーがindex.phpをロードしたときには、状態はスクリプトのリクエスト(GETやPOSTデータなど含む)、$_SERVERや$_ENVによって得られるシステムの情報、そのほかのスーパーグローバル変数によって定義されることになる。明白でないが、状態は現在の日付や時間なども含む。メソッド内で状態と言えば、渡されたパラメータ、メソッドがバインドされているオブジェクト(i.e. $this)に納められたもの、 そしてグローバルにアクセス可能なそのほかすべてのものが含まれる。

副作用 :この概念は状態と密接に関連する 副作用 とは、メソッドやそのほかのルーチン実行中に自分のスコープの外で引き起こす変化のことを指す。副作用には、グローバル変数の値、オブジェクトのプロパティ(i.e. $this)などが変更されることや、データベース、ファイ縷々システムに対する変更、参照渡しによるパラメータの値の変更、さらにはechoによる出力なども含む。

可変性 :可変性とは、ものが変化できる性質を持つことを指す。PHPにおける可変性の典型的な例は、変数やオブジェクトのプロパティにみられる。対照的に、不変性とは変更できないことを指す。たとえば、すなわちグローバルまたはクラスレベルの定数がそうだ。したがって、 可変性な状態 とは、変更可能なアプリケーションの状態(上記参照)の1要素と言うことができる。これらの変更が、いわゆる副作用を引き起こすもの、である。これは、明らかに見えるかもしれないが、後でもっと重要になってくる。

参照透明性 :渡されたパラメータのみによって返値の値が決まり、また自分のスコープの外の状態に対して何の副作用も発生しないという、メソッドや関数のもつ特質のこと。参照透過性を持つメソッドは、外部の状態を準備する必要がないので、テストするのが非常に簡単である。同じ値を渡せば、必ず同じ出力が得られるからである。また参照透過性を持つ関数は、キャッシュするのも簡単だ。同じパラメータであれば何度呼び出しても同じ結果が返るからである。このプロセスは、 メモ化 として知られている。


さて話を元に戻すと、よく言われている静的なもののテストが抱える問題点とは、変更可能なグローバルな状態と関わらなくてはいけない、ということですね。例として、いつ変更されるかわからない外部の(通常はグローバルな)情報に依存しているスタティックメソッドなんかをテストする場合のこと。シングルトンは、このアンチパターンの代表例だね。シングルトンの背後にある考え方は、ある時点で使用可能なインスタンスが一つ(たった一つ)だけあるということだ。

この考え方の本質的な問題は、シングルトンの属性がどうなっているのか知るすべがないこと。だってアプリケーションのどこからでも、それらを変更することができるわけだから。これは、ほぼすべてのソフトウェアがもつロジック的なバグの原因となっていることを証明しているように思う。唯一の解決策は、シングルトンの設計を、一度生成されたら属性を変更することができないように(つまり不変に)することだろう。 もしくは、シングルトンが必要ないような構造に設計しなおすか。

幸いなことに、Lithiumのすべての静的クラスは参照透明性なメソッドか、利用パターンとして不変を要求させるようなメソッドによって構成されている。 いくつか例を見てみよう。参照透明性のメソッドとしては、lithium\util\String::insert()はテンプレート文字列に値を挿入した文字列を返すし、lithium\util\Inflector::camelize()は単語や文章の別バージョンを生成します。これらの関数は外部に副作用を発生させないし引数だけによって決まる値を生成します。

不変な静的クラスの例としては、Adaptableを継承するクラス、例えばCacheやConnectionなどがあります。これらのクラスは、システムレベルのリソースへのアクセスを形成し提供してます。例えば、データベースへの接続、ユーザーのセッション、キャッシュの構成などです。これらのクラスは、どうやってアクセスするか、操作するかという情報を config()メソッドで得られる情報によって設定します。これは、アプリケーションのブートプロセスの間に、一度だけしか起こりません。そのクラスに対する以後のアクセスは(たとえばadapter()メソッドを通して)、いつも同じ属性を持った同じアダプターインスタンスが返されます。これにより、我々の水面下でアプリケーションの状態が変わってしまうことによって起こる問題を回避できます。

別の問題としてよく言われるのは、静的なもののテストはmockを用意するのが難しい、もっといえば依存性を取り替えるのが難しいことでしょう。以下の例を考えてみます。
class A {
   public static function foo() {
       // return some calculated value
   }
}

class B {
   public static function bar() {
       $result = A::foo();
       // perform some calculation on $result
       return $result;
   }
}




この例では、
B::bar()呼び出しはA::foo()を呼び出しています。Aへの呼び出しをしないでBを単独でテストすることは不可能です。PHP 5.2までは、解決策はありませんでした。しかし、PHP 5.3で"動的な"静的メソッド呼び出しを使うことで、次のようなことが可能になります:


class B {
   public static function bar($dependency) {
       $result = $dependency::foo();
       // perform some calculation on $result
       return $result;
   }
}




これで、
Aをほかのクラスに交換することができるようになり、Bをテストするのがとても簡単になりました。$dependencyはテストの時には別のモッククラスの名前に置き換えることができるからです。これはまた、Bの設計をもっと柔軟にすることができるという好ましい副作用ももたらします。

Lithiumはこの依存性の問題に対応するため、プロテクテッドな$_classes属性を一貫して使っています。次のコードはlithium\action\Dispatcherの一部です。


class Dispatcher extends \lithium\core\StaticObject {

   // ...
   protected static $_classes = array(
       'router' => 'lithium\net\http\Router'
   );
   // ...
}

Dispatcherの依存関係は動的に変更することができるように設計されています。別のルーティングクラスに変更することも可能です。これにはconfig()メソッドを使います。内部的には、Routerの呼び出しは以下のようになっています。


$router = static::$_classes['router'];
$result = $router::process($request);

すべての依存関係がこのように構成されているわけではありませんが、フレームワーク全体で使われている大事な規約です。例外として、変更できない依存関係はユーティリティメソッドへの依存であり、これらは参照透明性が保証されている場合がほとんどです。なので、ハードコーディングされた依存関係があるからと言って、テストが難しくなったり複雑になることはありません。



2010-09-01

プロパティにブロックを設定したい場合にいつも忘れるので記録

@property (nonatomic, copy) void (^callEventHandler)(CTCall*);

括弧の中に ^ と宣言したい名前を書くと。はい、覚えましたね。

copy じゃなくて retain でもいいんだろうか?

2010-08-10

ブロックを使うとiPhone OS 3での動作は不可能ということを再度確認

個人的にはiOS 4以前のコードは書かないことに決めていますが、そうはいってもお仕事です。未だにiPhone OS 3向けのビルドも作ってます。でも一度ブロックの使いやすさを味わってしまうと、もうなんか使いたくって仕方のない状態。なんならiOS 4専用の部分だけでも条件分岐を入れてブロック使わせてもらっていいかな?という検証。

結論:ブロックを使ったコードがバイナリに含まれているとdyldのリンクエラーで起動すらしません。


Tue Aug 10 12:48:26 unknown UIKitApplication:xxx[0xd506][2007] : dyld: Symbol not found: __NSConcreteStackBlock
Tue Aug 10 12:48:26 unknown UIKitApplication:xxx[0xd506][2007] :   Referenced from: /var/mobile/Applications/5DBA5BE0-0517-4ABB-AF15-C4006334BF74/Xxx.app/xxx
Tue Aug 10 12:48:26 unknown UIKitApplication:xxx[0xd506][2007] :   Expected in: /usr/lib/libSystem.B.dylib

まぁ、自分のアプリケーションだったらコードもコントロールできるけど、使っているライブラリなんかがブロック使い出したら、iPhone OS 3向けのビルドはもう作れないと言うことですな。

2010-07-28

駅ベル - 1.1.0 バージョンアップのポイントをまとめました


  • 駅までの距離に従い、精度を上げるようにした
    • アラームが正しく動作する率がアップ
    • 目的地まで遠い場合にはバッテリーの持ちアップ
  • iPodで音楽再生中にも、ちゃんとアラームが鳴るように
  • バックグラウンドでも、正しく音が鳴るように
  • バックグラウンドでも、バイブレーションが動作するように
  • 設定画面を追加
    • アラームの音を変更可能に(4種類内蔵)
    • バイブレーションを選択可能に(iPhoneのみ)
    • アラーム開始距離を変えられるように(右図)
  • iPhone 4 Retina Display対応(持ってませんが)

実は今回の一番の見所は、内部のロケーションマネージャの使い方を1から見直して、完全に新しい実装で書き直しました。本当に最小限の必要としている部分でしかロケーションマネージャーを使わないように細かいチューニングを行ったので、バッテリーの持ちは前のバージョンよりもかなりよくなっています。使っているときはステータスバーのロケーションインジケータが出るので、画面ごとに出たり消えたるすることで確認できると思います。

ロケーションマネージャについては、iOS4のマルチタスキングの売りの一つだけに、バッテリーの持ちとの新たな戦いの部分、別エントリーで書きます。

駅ベルのバージョンアップでリジェクト食らいました。その顛末。

今回の駅ベルのバージョンアップは、バックグラウンドで音が鳴らないという部分の対応。UILocalNotificationに任せておけばいいかなと思ってたんですが、ちゃんと音が鳴って欲しいという要望が強く、対応することに。

長いWaiting for reviewの期間を過ごして、なんといきなりリジェクト。その理由がこれ。
We've completed the review of your application; however, because no audible content is played when the application is in the background, we cannot post this version to the App Store. We have included additional details below to help explain the issue. We hope you’ll consider revising and resubmitting your application.
iOS4向けのマルチタスキング対応アプリケーションの一つの機能、バックグラウンドでの音声再生機能を使いたいためにフラグを付けたんだけど、それが裏目になった模様。おまえのアプリケーションは音を出して内じゃないか、と。ふーむ。

そりゃぁ、カリフォルニアではまだ鳴らないっつーの(笑)。どうもアプリケーションの動作を正しく理解してもらえてない模様。普段なら慌てるところですが、どうせ自分のアプリケーション、落ち着いて対応してみました。一度Rejectedになっちゃっているので、バイナリを再度アップロードしないでも再審査してくれるか不明だったので、ちゃんと行くかどうかのテストケースになります。

いろいろ騒ぐ前に、まずはちゃんとレビューチームとコミュニケーションを開始することが一番です、と言うアドバイスももらったので、まずはメール。

Dear review team,
My application uses audio to notify user as alarm sound. My application has to play sound in background mode, and I have no idea without adding "audio" flag. 
The Apple engineer I met at the WWDC Lab said, only way to play sound is to add "audio" flag in UIBackgroundModes. If still you reject my app, please tell another way to play alarm sound in background. I think that's not fair.
- My app plays audio when the device close to the station.
- Playing audio in background needs "audio" flag in UIBackgroundModes.
Other audio application can be paused. My application is also paused until it reaches to destination, isn't it?
Please re-think about this.
Yosuke Suzuki
で、その晩はMOSA entranceがあったので、その場でリジェクトくらったーとネタにしてたりしていたんですが、裏ではことが進んでおり、今朝になってメールが届いてました。

Thank you for you email and clarification.  We are proceeding with the review and will update you with further status as soon as we are able.
Thank you for your continued patience.
短い。あまりに短いが、そしてアメリカ人、決してわびの言葉はないが、ちゃんとスムーズに対応してくれました。
無事にリリース。

教訓。リジェクトされても慌てず騒がず、ちゃんとレビューチームとお話しはしましょう。返事もくれます。他の「Contact us」系のメールと違ってスムーズです。


2010-07-08

CoreDataと再度向き合うことを決定。その前に前回の反省。

昨年からやってるランブリンのデータ部分、当初CoreDataを使っていたんだけど、どうにも使い勝手も悪く感じて、とどめはマイグレーションではまってバージョンアップでトラブル。これでもう、次のバージョンは自分で作ったCoreDataぐらいの互換レイヤーに切り替えよう、というのが今年の2月。

ある程度の時間をかけてMoreDataと言うモノを作り上げて、ランブリン 2.0のコアに使ってみたんだけど、結論から言うとあまり芳しくない状況。特にメモリ効率が極端に悪くなってしまったのが大きな誤算。SQLの使い方にはある程度自身があったんだけど、スレッド・セイフティの確保やフォルトの仕組みなんかを入れていくと速度も芳しくなく、使い勝手やマイグレーションの仕組みは直接的でよかったんだけど、全体的にいわゆる失敗と判断せざるを得なくなってしまった。

メモリ周りはやっぱり難しくて、要はキャッシュの話。何をいつ忘れるのか、これを正しく実装するのが至難の業。iOS4にはNSCacheというクラスが導入されているのも、キャッシュの難しさを表している一端と言えよう。

と言う状況で挑んだ今年のWWDC。事前に去年のビデオでCoreDataを勉強し、ドキュメントももう一度読みこんで、果たして自分はCoreDataの何を間違えていたのか、そういう視点でいろいろと検証していった。結論として


  • CoreDataをいわゆるデータベースととらえていてはダメ。単なるデータを保存する場所ではなく、データが生き続ける環境を提供してくれる環境であって、データをそこから取り出してしまっては、メリットの大半を消すことになる。
  • 同じ理由で、CoreDataを簡単なDBMに見えるようなラッパークラス経由で使ってはダメ。ちゃんとコンテクストを意識して、正しく使わないと意味がない。中途半端なSQLの知識が邪魔をしたのは否めない。
  • マイグレーションは後々絶対はまる場所なので、最初から経験を積んでおくべき。ライトウェイトだろうとなんだろうと、アプリを出した後は実際にデータがたまってしまった状況でテストも出来ないので、かならず各バージョンのデータファイルを保存しておくべき。後から手に入れるのはとても大変。
  • スレッドは最小限に。でも一つは使う。なのでNSManagedObjectIDは登場する。
こんな感じだと思う。もう一度CoreDataに手を出す前にまとめておきたかった。数ヶ月後に何を思うか。

2010-07-07

配列の配列からオブジェクトを探して、そのindexPathを返す例。powered by Block



表記になれればきれいに書けるな。スクリプト言語に慣れ親しんでおいてよかったなぁ。

2010-07-06

言語設定を変えるとバッググラウンドで走っているアプリは殺される

iOS4になって、アプリを開いている最中に環境設定も開けるようになったわけで、ドキュメントにもそれに備えろよ、と言うことは書いてありますが、じゃあ根本的な設定が変わったらどうするの?と。その最たるモノが言語設定。途中で変わると画面から何から作り直さなくてはいけないので、どうなるかと試してみた。
まあ、当たり前と言えば当たり前だが、アプリは黙って殺されます。初期化にし直しましょうと言うことでしょうか。

NSStringのフォーマット文字列生成で位置指定が出来る!

NSStringのフォーマット文字列生成で、 %n$@ というのが使える! (nは数字)

これまでは、必ず

[NSString stringWithFormat:@"Hello %@, (%@)", param1, param2];

のように順番に使われるしかなかったんですが、


[NSString stringWithFormat:@"Hello %2$@, (%1$@)", param1, param2];

のようにすれば、コード中の順番に関係なく文字を埋め込めると言うことです。
知らなかったよ、早速試してみよう。


※ 数字は1から始まるので注意。

ネタ元 : WWDC 2009 Session 106 - Building Localized Mac and iPhone Applications

2010-06-30

古いXcode用のアイコンを作ったよ - Xcode aged


http://bit.ly/aIshfv

焼けた青写真てな感じにしてみました。もう、Xcodeだらけでわかんないから!

icnsファイルなので、Xcodeのパッケージを開いてResourcesの中に突っ込んでね。

2010-06-24

駅ベル - 乗り越し防止アラーム

iPhone 4で盛り上がる中、ようやくバスケ個人名義の最初のアプリ。「駅ベル」が公開されました。

http://itunes.apple.com/jp/app/id377891789?mt=8 #iTunes

駅ベルとは何か?簡単に言えば、目的の駅に近づいたらアラームを鳴らしてくれるソフトです。全国の駅情報をekidataさんからいただきましてアプリ内に最初から収めてありますので、簡単に目的地を探すことができます。

そして、なんと言ってもiOSの各種機能に対応しています。Fast App Switchはもちろん、iOS4の目玉、マルチタスクにもちゃんと対応しています。バックグラウンドにいても監視は続けますので、ウェブをみたりゲームをしていても大丈夫です。Local Notificationを使ってアラート画面が表示されます。iOS 4で追加された新しい位置情報取得の仕組みを使っているので、これまでのアプリよりもバッテリーの減りも少なくてすんでます(それでも結構使いますが)。バックグラウンドに回ったときの挙動も、WWDCで学んだことは実践してますので省メモリ化もできているはず。

このアプリ、SDKが公開された2年前から作り始めたモノで、なかなか完成しなかったのです。だって監視している間アプリを終了させられないわけで、できることと言えば音楽を聴くことだけ。電源をスリープにしてしまうと、位置情報の精度がまったく当てにならず。アプリ内にブラウザを入れたりTwitterみれるようにしたり、いろいろ工夫してみたんですがどうもしっくりこず。

が、iOS 4になってアプリを後ろに回せるようになったことでがぜん盛り上がりました。ちゃんと位置情報もバックグラウンドにいながら取得できるわけで、これはオレのためのアップデート!wと勝手に理解して一気に仕上げました。と言うわけで無事iPhone 4の発売日にリリース。

しかし、長かった〜。リリースまで2年3ヶ月は自分の中でも最長記録。この二年間、各所でデモなんかをしてましたが、会う人会う人に、あれまだ出てないの?となじられてきましたが、それも今日まで。胸を張ってリリースされてます!と言えますよ。でましたよ!

2010-06-18

WWDC 10 - みとくべきセッションビデオ

全部なんだけどねw

とりあえず自分がみたセッションで面白かったモノ、見逃したモノを列挙。随時更新していきます。


Session 116 - Model-View-Controller for iPhone OS
リピートセッションまで行われた人気セッション。参加者曰く、刺激になりますよーとのこと。
実際のところMVCを考えるための現実的解を示してくれます。これはいいセッション。

Session 207 - Network Apps for iPhone OS, Part 1
Session 208 - Network Apps for iPhone OS, Part 2
ずっと昔からDTSで活躍するQuinn the Eskimoさんがネットの難しさを語ります。Part2は必見。RunLoopとスレッド。GCDの時代はまだやってこない、など。


Session 103 - iPad and iPhone User Interface Design
毎年同じような内容と言いながら、iPadでいったんリセットされた似等しいインターフェースデザインについてみときたい。面白かった。

Session 104 - Designing Apps with Scroll Views
長蛇の列ナンバー1だったかもという人気セッション。ScrollViewの入れ子構造で実現する写真アプリの作り方。

Session 105 - Adopting Multitasking on iPhone OS, Part 1
Session 109 - Adopting Multitasking on iPhone OS, Part 2
iOS 4の見所No1のマルチタスクについては必見。

Session 107 - Cocoa Tips and Tricks
あの人が出ます。

Session 115 - Using Core Location in iOS 4
ローケーションの取り方がだいぶん変わってます。バッテリーに気を遣いたいアプリを書きたければ必見。

Session 206 - Introducing Blocks and Grand Central Dispatch on iPhone
Session 211 - Simplifying iPhone App Development with Grand Central Dispatch
ようやく使えるようになったブロックとGCD。

Session 423 - Sensing Device Motion in iOS 4
ジャイロが追加されたセンサー系をまとめる CoreMotion フレームワークの唯一の情報。

Session 300 - Developer Tools State of the Union
今回はツール系のフィーチャーしっぷりがすごかった。その最初としてこれだけは観とくべき。

Session 304 - What's New in Instruments
何がすごいってこんなツールを提供するアップルがすごい!

Session 306 - Automating User Interface Testing with Instruments
JavaScriptを使って自動化よ! 繰り返しテストが楽になります。多分。

Session 505 - Creating Extensions for Safari, Part 1
Session 506 - Creating Extensions for Safari, Part 2
すごく簡単に作れる。概念も理解しやすい。今日から、作るべし。

Session 130 - Future Proofing your Application
将来にわたって安心して動くアプリを作りたければ、という内容。ちょっと期待はずれではあるがみとくと言い訳になる。

まだみてないやつ。

Session 138 - API Design for Cocoa and Cocoa Touch
CocoaのAPI設計の妙を学ぶ。


2010-06-17

iOS 4のマルチタスクへの対応

前のポストで、そもそもiOS 4に対応するフェーズをまとめました。で、iOS 4に対応するとした場合、どの機能に対応するとどうなるかをまとめます。


高速アプリ切り替え
SDK 4.0でビルドすると自動的に対応します。ただし、マルチタスク自体のアプリとしては、裏に回ったときの正しい作法というものがありますので、それに従った動作が求められます。


バックグラウンド・オーディオ
Info.plistでバックグラウンドでの再生を希望する旨を記述しておくと、バックグラウンドに回った場合の音の再生処理が継続して行えます。アプリ側で特別にやらなくてはいけないことは増えませんが、メモリの使い量、I/Oの使い方など工夫しなくてはいけなくなると予想されます。

Voice over IP

Info.plistでVoIPを実装したいと記述しておくと、インターネット電話を実現するために必要な待ち受け接続への対応をシステムがやってくれます。起動し続けなくても、必要なときに起こされます。標準の電話アプリと同じような立ち位置になれると言うことです。実装は大変でしょう。

バックグラウンドロケーション
Info.plistでロケーションを取得したいと記述しておくと、バックグラウンドにいるときも位置情報を取得できるアプリが作れます。バッテリーのことを考えると一番やっかいな種類のアプリです。

タスクの完了待ち
これら上記の特定用途のマルチタスク機能と関係なく、すべてのiOS 4対応アプリは、バックグラウンドに回る前に一定期間の猶予が与えられます。まだ仕事完了してないよって場合には、ブロックで処理を記述して実行させることができます。この処理が終わるまでサスペンドはされません(見た目上バックグラウンドに回ったことにはなります)。一定時間を過ぎてもタスクが終わっていない場合、システムのやつは勝手に殺すぞと言ってますので気をつけましょう。

ローカル・ノーティフィケーション
上記のバックグラウンド処理がユーザーに通知するUIとしてローカル・ノーティフィケーションが追加されてます。

これ以上の詳しい情報は、iPhone developer登録をすればドキュメントで見れますので、各自調べること。

iOS 4への対応の仕方まとめ

未対応iOS 4テスト済みiOS 4対応
ビルドするSDK※1~ SDK 3.2~ SDK 3.2SDK 4.0 ~
iOS 4で動作するか?わからんするする
OS 3.1で動作するか?するするする※2
バックグラウンドで動作しないしない可能※3
サスペンドするか?しないしないする
アプリ切り替えリスト※4に並ぶ並ぶ並ぶ並ぶ
高速アプリ切替非対応非対応対応


※1 Base SDKのこと
※2 Deployment TargetがiPhone OS 3.1以前になっていれば
※3 追加で設定、コードの記述が必要
※4 マルチタスク切り替えのために画面の一番下に出るアプリのリスト

2010-06-03

PHP 5.3

いまさらながらPHP 5.3と向き合う。もうPHPなんかに期待しないよ、仕事でみんなと使う言語だよ。面白いことはPythonでやるよ、とPHPを見捨ててから3年。PHP 5の進化もまったく注意も払っていなかった。今更どうにもならんだろうと。

さて、今年。自分的には今のところ激動の2010年なのだが、いろんなテクノロジーがPHP 5.3へバトンをつなげてくれた。

KVS → Tokyo Tyrant → MongoDB → Lithium → PHP 5.3

実は5.3のことはあまり知らず、6.0へのつなぎ、内部文字コードがUnicodeになるよー、覚悟しとけバージョンだと思い込んでいたら、実はとてつもなく強力な機能が投入された、まるで別の言語になっていた。その二つとは、無名関数と名前空間。

無名関数=名前のない関数、昔はそんなものがなんに役立つのと思っていたが、最近のコーディングを振り返ってみると何でなくてやってこれたんだ?という思いになる。イベント駆動型のプログラミングを今までもやってく体他が、かなりの苦労と意味のない名前、特に日本人にとっては頭の切り替えを必要とする英語名をつけなければいけないという作業をやっていたことになる。

「この作業をやって欲しい、中身はこれこれこうだ」
「わかりました、それでこの作業に名前はなんでしょうか?」
「名前が必要なのか?やることはわかっただろうに」
「名前が必要なんです。決まりです」
「じゃあお掃除処理でいこう」
「すみません、英語でお願いします」
「…」

名前つけなくてよければ、これお願いですむところを、余計な頭を使わされていたことがわかる。無名関数万歳。関数が変数に入れられるとか、そういう恩恵以上に大事な要素と思う。

そして名前空間。過去に「結局クラスって名前空間、責務の分離だよね」という暴論をはいたことがある。若さ故の過ち、でも名前空間はそのくらいの大事な要素。これはクラスという機能をねじ曲げてでも名前空間が欲しいという気持ちの表れと今は擁護したい気持ちでいっぱいだ。

またPHPはここでも論争の的となるチョイスをしている。名前空間の区切り文字にバックスラッシュを採用している。もーっ!とも思うんだけど、これはたいしたことではないなと。もたらされるメリットのためなら目をつぶる。無視できる範囲。変数に$、メッセージ送信に->と同じレベル。いちいち語尾に「じゃん」とか付けるなよ的な。

ということでLithiumとともにしばらく遊んでみたいと思う。幸いSnow LeopardはPHP 5.3なので問題なし。ローカルで試せるのがうれしい。

2010-05-18

EC2のFedora8インスタンスにgitをインストールするのに最低限必要なパッケージ一覧

いつもインストールにはまるので。エラー出すの遅いよ。ぶつぶつ。

yum install gcc zlib-devel openssl-devel curl-devel perl-ExtUtils-AutoInstall perl-ExtUtils-Embed perl-ExtUtils-MakeMaker perl-ExtUtils-MakeMaker-Coverage asciidoc xmlto python-devel docbook2X

2010-03-27

SharedCenterというクラスを書いてみた

Cocoaでユーティリティ的に使うクラスの定番パターンで、singletonパターンがあります。NSNotificationCenterがいい例で、アプリケーションワイドで使う機能をクラスにする場合に便利なパターン。こんな感じ。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sayHello:) name:HelloWorldNotification object:nil];

これに従って、自前で作るシングルトンクラスもなんちゃらセンターと言う名前で作りがちです。僕の場合、


  • SupportCenter
  • ActivityCenter
  • DownloadCenter

などなど。それぞれのクラスにクラスメソッドとしてsharedCenterというメソッドを定義して使ってます。こんな感じ。

[[SupportCenter sharedCenter] alertError:error];

このパターン、便利なんですがコードの中では結局グローバル変数を使って管理するという、まああまり見たくないコードでして、アナライザーに文句言われないためにもちゃんと終了時にグローバル変数を破棄してあげる必要があったり。簡単なことだけどちょっと面倒くさい。

というわけで、メタに考えました。シングルトンを管理するシングルトンクラス、SharedCenter。

SharedCenter.h
//
//  SharedCenter.h
//  Ramblin
//
//  Created by Yosuke Suzuki on 10/03/27.
//  Copyright 2010 Kanshin, Inc.. All rights reserved.
//

#import <foundation/foundation.h>


@interface SharedCenter : NSObject

+ (id)center:(Class)cls;
+ (void)registerCenter:(id)center forClass:(Class)cls;

@end

SharedCenter.m
//
//  SharedCenter.m
//  Ramblin
//
//  Created by Yosuke Suzuki on 10/03/27.
//  Copyright 2010 Kanshin, Inc.. All rights reserved.
//

#import "SharedCenter.h"


@implementation SharedCenter

static NSMutableDictionary *sharedCenters = nil;

+ (void)initialize {
  sharedCenters = [[NSMutableDictionary alloc] init];
  
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeCenters:) name:UIApplicationWillTerminateNotification object:nil];
}

+ (id)center:(Class)cls {
  id center = nil;
  
  @synchronized(sharedCenters) {
    NSString *className = NSStringFromClass(cls);
    center = [sharedCenters objectForKey:className];
    if (!center) {
      center = [[cls alloc] init];
      [sharedCenters setObject:center forKey:className];
      [center release];
    }
  }
  
  return center;
}

+ (void)registerCenter:(id)center forClass:(Class)cls {
  @synchronized(sharedCenters) {
    [sharedCenters setObject:center forKey:NSStringFromClass(cls)];
  }
}

+ (void)closeCenters:(NSNotification *)notification {
  [sharedCenters release];
  sharedCenters = nil;
  
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

このクラスを使えば、どんなクラスでも簡単にシングルトンパターンが使えます。しかもグローバル変数は一つだけ。すっきりです。

SupportCenter.h
@interface SupportCenter : NSObject {
...
}

+ (SupportCenter *)sharedCenter; // 定義を追加
...

SupportCenter.m
#import "SupportCenter.m.h"
#import "SharedCenter.h"

@implementation ActivityCenter

// 実装を追加
+ (ActivityCenter *)sharedCenter {
return [SharedCenter center:[self class]];
}

...

2010-02-03

gitのリモートのブランチを削除する方法

$ git push origin :ブランチ名

コロンの意味がわかんないけど、とりあえず忘れないように。

Diplomacy on iPadを作る計画。

2010年、今年の個人的な目標、iPad用のアプリとしてディプロマシーを作る。iPadでやると、マップの操作性も戦術練るにもいろいろ出来そうだし、秘密交渉の演出も素敵にできそう。秘密文書が届くとか。チャットとか。あーカメラがついていれば。

Diplomacy MOE
Web上で遊べるディプロマシー。これがお手本になるはず。参考にさせてもらいます。

AppStoreのバージョン番号ではまる


ランブリンのバージョンアップ版をリリースしようと昨夜から奮闘した記録。

最初のバージョンが1.0でだして、次のマイナーアップデート版を1.01でだしました。ここまでは問題なかったのですが、昨日出すものが機能的にも増えたこともあり、1.02ではなく1.1にしましょうと決定しました。

で、いざリリースの段階になって、サブミットしてみると

The binary you uploaded was invalid. The key CFBundleVersion in the Info.plist file must contain a higher version than that of the previously uploaded version.
 これは困った。でGoogle様に聞いてみたところ、iPhone Dev SDKに記述を見つけました


Registered Member

Join Date: Jul 2009
Posts: 8
Just went through this process with fairly simple version numbers and here's what I found;

Original version '1.0'.

Next upgrade version '1.01' - worked fine.

Tried to submit an upgrade to version '1.1' and got the "CFBundleVersion in the Info.plist file must contain a higher version than that of the previously uploaded version" error.

After much messing around with the package including check the version in the package contents of the built program submitted as version '1.10' and it worked.

Seems like there is a problem with the string to float conversion that Apple is doing.


なるほど、1.01 の次は 1.10ならオッケーなのか。ではそれで...って1.10ってなんだよ!「十」ってなんだ。マイナーバージョン10はないだろう。SuperClock 3.9.10 ぐらいしか聞いたことないぞ。これはそのまま採用しづらいな。


じゃあ、1.1.0 ならどうだ。これならまだ意味は通じるので再度チャレンジ。さて...失敗。


orz




やっぱり1.10しかないか。とバイナリーは作り直して、ふと思う。表記上はあくまで1.1.0としたいのでiTunes Connectでの表記と変えてみてはどうなるか。前に一致してないからダメだよ、といわれたんだけど物は試し。エイヤっとアップしたら、なんと問題なく通った!おぉ、じゃあAppStoreにでるバージョン表記とBundleVersionは関係ないのか?関係がないならいっそ違う番号体系になっているほうが間違いは少ない。ということで、最終的には


iTunesConnect Version = 1.1.0
Info.plist CF Bundle Version = 2


という状態でアップしました。問題はなし。


混乱を極めたバージョン問題ですが、結局見た目のバージョンと内部バージョンを分けるというのがベスト。AppStoreにバイナリーをサブミットしたときに言われエラーは、結局内部バージョンを上げなさいということ。そのバージョンと表記上のバージョン(テキストフィールドにいれるもの=ユーザーの目に触れるもの)は別と考えたほうが混乱はない。だいたい戦略上の理由で見た目のバージョンは決められることも多いし。


ただし、アプリ内のバージョン表記も必要で、これは今までCFBundleVersionKeyを参照していたので、新たにDisplayBundleVersion という項目を追加しました。今後箱の二本立てで管理することにします。

2010-01-29

iPadにはプラグインの仕組みが欲しいな

iPhoneにはプラグインは必要ないかと思ってた。画面も小さいしアプリの規模もそんな大きくない。解決したい物事に特化した単機能の小さいアプリがたくさんそろっていればいいかなぁと。

でも、iPadは事情が違う。移動中に使うというよりは、リビングとかデスクとかカフェとか、落ち着いた場所でじっくり使うモノになりそう。画面もでかいしアプリが出来ることもどんどん高度になっていく。裏を返すと、その分アプリを作るのが大変になる。

例えば、とてもじゃないけど、Pagesに対抗するワープロアプリを書こうなんて考えもしない。書けたとしたら$10じゃ売れない。とても無理。

そしたら、iPadにもiPhoneのアプリみたいに、シンプルなソリューションを提供する場所が必要だと思う。もちろんこれまで通りアプリ作ればいいってことも多いとは思うけど。組み合わせたい機能というのはたくさんある。

例えば?

  • テキストの編集中に表示されるメニューに翻訳機能を提供したい
  • 写真ライブラリの共有メニューに、うちのサービスへのアップロード機能もつけたい
  • Pagesの書類を別の形式で書き出したい
...あんまりないか(笑)。まあ、次の主戦場はアプリではなくもっと機能に集中させて欲しいなぁ、というのが開発者の希望なのかな。AppStore、アプリ内課金、ときたので、機能別課金、PluginStoreみたいなことをやってほしい。

ちなみに、プラグイン機能をつけるとセキュリティ的にやばい、というのは、アプリがみんな好き勝手に自分の独自実装で機能を拡張しようとした場合で、システムがプラグインを管理し、データ中心名設計をすれば問題なく仕組みは作れると思います。どうせStore経由でしか取得できないんだろうし。


2010-01-25

Objective-C 2.0 ローカルカテゴリの書き方

@interface Hello : NSObject {
 ...
}




@interface Hello()
- (void)world;
@end

@implementation Hello  // ←()のないメインの実装の中に書く

- (void)world {
}

@end

2010-01-05

2010年 - Smalltalkを体験する年

以前から @sumim さんからさんざん言われていたが、年末に呑んだときに話の流れでこういうことに。Smalltalkのすごさがわかる本書いてよ、といったらパーソナルなツールとなるもの、とても万人に向けてよさを伝える本は(面倒くさくて)書けない、結局one to oneでないとよさは伝えられないよ。ということで、聞いてくれたら答えてくれるそうなので勉強してみようという次第です。どうなることやら。

まずは環境構築からだな。うちにあるSqueak入門読んだほうがいいのかな。一回は読んだ気がしますが。

ともかく悩んだら考える前に聞いて、という夢のような先生なので、期待してます。

ブログ始めました

2010年、今年はブログを始めてみようかと思います。