[Titanium]window.urlが駄目な理由

sxchu_1276335_threads.jpg

[Titanium] window.urlは推奨されないプログラミング手法らしい – もぎゃろぐの続きです。

つい先日まで使っていた物を突然駄目だと言われても納得が出来ないと思うので、どういう場面で困ったことになるのかの例を一つ。

ある程度大きなプロジェクトになると、アクセスクラス付きのデータクラスみたいなのを作りたくなることがあります。たとえばこんなクラス。

var Obj = function(){
this.v = 1;
}
Obj.prototype.setVar = function(v){
this.v = v;
}
Obj.prototype.getVar = function(v){
return this.v;
}
var obj = new Obj();

obj.vを直接書き換える代わりに、セッターとゲッターを用意しておくことで、例えばセットした時にログを書くとか、セットする時に不正な値だったらはじくとか、いわゆるカプセル化のクラスです。
この状態で、objをあちこちの画面で共有したいとします。

var Obj = function(){
this.v = 1;
}
Obj.prototype.setVar = function(v){
this.v = v;
}
Obj.prototype.getVar = function(v){
return this.v;
}
var obj = new Obj();
var win = Ti.UI.createWindow({});
win.obj = obj;
win.obj.setVar(2);
Ti.API.debug('app.js win.obj.getXXX:'+win.obj.getVar()); // 1が帰ってきてしまう

obj.setVar(2)で値を渡したはずなのですけど、newした時の値が帰ってきてしまいました。
この例では簡単にテストするためにファイル一個でやっていますが、winの定義を別ファイルに分けても再現します。

なんでこうなるの?

Ti.UI.createWindowで生成したオブジェクトは、JavaScriptのオブジェクトみたいに振る舞っていますけど、実際にはObjectiveCやJavaのオブジェクトにリンクされています(そうじゃないとネイティブUIの部品を画面に出すことが出来ないですからね)

ここからは推測なのですけど、そうやって生成されたWindowオブジェクトのプロパティに値を代入する(たとえば、win.obj = obj; のように)と、JavaScriptとObjectiveC/Java言語の壁を越えるために、いったんJSON文字列に変換されてしまいます。

結果としてメソッドは生き残ることが出来ないので、obj.setVar()がまともに動作しなくなります。

それだったらいっそ例外になってくれれば良いと思うのですけど、中途半端に動くあたり、もしかしたらJSON化じゃなくてもう少し別の実装になっているのかもしれない。その辺はちょっと自信なしです。ソース追ってみたんだけど糸口がわかんなかった(><)

オブジェクトはコンテキストを越えられない

ちょっと底の浅い説明になってしまいましたけど、ともあれ、obj.setVar()が動作しないことは事実です。この現象は、Windowオブジェクトに限らず、Ti.Appのプロパティとして割り当てても同じ現象が起きます。要するに、Ti.のプロパティにメソッドがついたオブジェクトを引き渡してはならない、ということです。

なぜwindow.urlを使ってはいけないのか。
window.urlスタイルのプログラムを使うと、上記のようなメソッド付きのオブジェクトを共有する手段がなくなってしまうからです。

単に数値や文字列を画面間で共有したいだけであれば、windowのプロパティに渡してもいいし、相互に変更をやりとりしたければ、Titanium.App.Propertiesを使うこともできます。
このやり方で実装してしまうと、各画面がロジック部分まで持つことになるので、UIとロジックを分離することが困難になってしまいます。
UIとロジックを分離するためには、メソッドの共有がどうしても必要なのです。

公式ビデオの三本目、Building Native Mobile Applications 03 – UI Fundamentalsでは、こんなふうに説明されていました。

「真っ平らな地面」が必要な場合のみ、マルチコンテキストを使う意味がある。KitchenSinkは、たくさんのデモを見せるための物で、互いにデータを共有する必要がなかったからマルチコンテキストが使われている。

あと、ロジック部分は全部インターネット上のサーバにあって、各画面はWebAPIを叩くだけ、というアプリも、マルチコンテキストで実装しやすそうな気がします。TitaniumMobileが得意とするカタログアプリみたいなのですね。