TitaniumMobile勉強記

Web系エンジニア向けのキャリアアドバイザーやってましたが現在はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連(Node.js、Titanium)あたり

Ti.Database.open使って情報が読み取れない原因がわかりました

まずは現在困っていることのまとめ

うちの会社で運営しているあすなろBLOGのビューワーアプリを作っているのですが、過去エントリについてはRubyで書いたクローラ使って収集済。

そのため過去エントリについては、SQLite上にすべて突っ込んでおき、適宜そこから読み込むような処理にしようと思って実装したのですが、エミュレータでは表示されるものが、なぜか実機に転送すると表示されないという症状に出会ってずっと悩んでます

iPhoneEmulator上の結果
f:id:h5y1m141:20120128075928p:image

実機へ転送した結果
f:id:h5y1m141:20120128075927j:image

Ti.Database.open 使わずにTi.Database.installなら動作する

少し前ですが

エミュレータだと動作するのに、実機転送したらno such table:entries..っていうエラー吐いてアプリケーションエラーになる。TiDatabaseProxy.m:136というメッセージがこれ( http://bit.ly/ygU09w )と似た症状っぽいなぁ
過去のtweetより

Ti.Database.openじゃなくって、代わりにinstall を利用しつつ、念のためdatabase保存先をこちら参考( http://bit.ly/u2seuS )にしてコード書き換えたら実機でも動いた。
過去のtweetより

ということをつぶやいた通り、install使うと実機でも意図したように表示されます

原因追求になんとなくつながったヒント

TiDatabaseProxy.m:136 でググッていた中で

Problem Solved ! To generate the database I was using Firefox SQLite Manager and this addon was creating a Sqlite2 instead Sqlite3.
I had to create it by the command line (sqlite3 command).
http://developer.appcelerator.com/question/124705/app-crashes-when-sqlite-database-is-instantiated:title=

というような一文をみつけて、これは自分とは違うから関係ないなぁーと思って、ひとまず気分転換のために、お風呂に入りました。

そしたら、神のお告げっていうわけじゃないwwけど、ふと

「そういえば、Rubyで書いたクローラからSQLite3にデータ保存したファイルを、/Users/xxxx/Library/Application Support/iPhone Simulator/4.3.2/Applications/xxx/Library/Application Support/database以下にコピペしてるけど、そのファイル形式とかに何か原因あるのかな」

ということを思いつき、ひとまずTitanium 側だけでSQLIteのデータベース生成、データ挿入、読み込み処理をすることができるか試すことにしました

var db = Ti.Database.open('blogData');
var blogData ={
  post_date:'2006/07/03 00:51:00',
  json:'{"permalink":"http://blog.pasonatech.co.jp/kanazawa/202/1686.html","html_body":"<p>先週金曜日、この日は月一度の全体ミーティングだった。<br>\n各事業部からの報告や、新しい動きの発表がある。<br>\n自分の知らないところで、みんながいろんなことをやってる。<br>\n自分もこれから先、いろいろなことをやっていきたい。<br>\nだけど、現在はいまの作業をまだまだ勉強中。<br>\n会社のいろんな動きの中で、自分は何ができるんだろうか…と焦りを感じてしまう。</p>\n\n<p>そして、毎月MVPならぬMDP(Most Drecomtic Person)と言って、<br>\nもっとも\"ドリコムらしい活躍\"をした人が投票で選ばれる。<br>\nこの候補に選ばれる人はいつもすごい人ばかりだ。<br>\n新製品をメインで作った人、企画を成功させた人、営業ですごい結果を残した人、新卒で初めて受注を取った人・・。<br>\n自分はというと、それにはまだまだ程遠い。<br>\nそれがなんとももどかしい。<br>\n自分も早く人に認められる成果を上げたい。</p>\n\n<p>そんなに簡単に成果を上げられる訳ではないこととは知っていても、何か焦りを感じてしまいます。<br>\nだけど、これは周りの人の活躍が良い刺激になっているということでもあると思う。<br>\nそういう人たちをいつも見て、自分の目標も高く持てるというのはいいことだと思っています。</p>","title":"刺激と焦り","post_date":"2006/07/17 22:29:00","blogger":"kanazawa"}'
};

db.execute('CREATE TABLE IF NOT EXISTS entries(post_date DATE, jsonData TEXT)');
db.execute( 'INSERT INTO entries (post_date,jsonData) VALUES(?,?)',            blogData.post_date,blogData.json);
var resultSet = db.execute('SELECT post_date, jsonData FROM entries order by post_date');
var arr = [];
while (resultSet.isValidRow()){
  arr.push(resultSet.fieldByName("jsonData"));

  resultSet.next();
}
var result = "[" +arr.join(",") + "]";
Ti.API.info(result);
db.close();
var list = eval(result);

根本的な原因はJSON文字列をSQLiteに保存する箇所のようでした

上記コード実行すると、

[ERROR] Script Error = {
line = 1;
message = "Parse error";
name = SyntaxError;
sourceId = 150463928;
}.

というエラーを吐いて落ちました・・なんで1行目でParse errorになるのか最初意味がわからなかったのですが、blogData.jsonをよくよく見たら、html_bodyの中で、ところどころ改行文字(\n)が含まれてて状態でeval() すればそこで改行されてしまい、結果Parse errorが生じているようでした。

そのため、改行文字(\n)だったり、「\"ドリコムらしい活躍\"」というようなダブルクォーテーションのエスケープ処理の所を編集して

var blogData ={
  post_date:'2006/07/03 00:51:00',
  json:'{"permalink":"http://blog.pasonatech.co.jp/kanazawa/202/1686.html","html_body":"<p>先週金曜日、この日は月一度の全体ミーティングだった。<br>\n各事業部からの報告や、新しい動きの発表がある。<br>\n自分の知らないところで、みんながいろんなことをやってる。<br>\n自分もこれから先、いろいろなことをやっていきたい。<br>\nだけど、現在はいまの作業をまだまだ勉強中。<br>\n会社のいろんな動きの中で、自分は何ができるんだろうか…と焦りを感じてしまう。</p>\n\n<p>そして、毎月MVPならぬMDP(Most Drecomtic Person)と言って、<br>\nもっとも\"ドリコムらしい活躍\"をした人が投票で選ばれる。<br>\nこの候補に選ばれる人はいつもすごい人ばかりだ。<br>\n新製品をメインで作った人、企画を成功させた人、営業ですごい結果を残した人、新卒で初めて受注を取った人・・。<br>\n自分はというと、それにはまだまだ程遠い。<br>\nそれがなんとももどかしい。<br>\n自分も早く人に認められる成果を上げたい。</p>\n\n<p>そんなに簡単に成果を上げられる訳ではないこととは知っていても、何か焦りを感じてしまいます。<br>\nだけど、これは周りの人の活躍が良い刺激になっているということでもあると思う。<br>\nそういう人たちをいつも見て、自分の目標も高く持てるというのはいいことだと思っています。</p>","title":"刺激と焦り","post_date":"2006/07/17 22:29:00","blogger":"kanazawa"}'
};
というデータをSQLiteに挿入→読取→TableViewに表示だと意図したように表示されましたー

実は以前に

色々悩んだ挙句、現時点でこういう形にしました。何も考えずにeval()するのって、なんとなく気持ち悪いがするので、入力値チェックしたほうが良さそう
http://d.hatena.ne.jp/h5y1m141/20110418/p1:title=

ということを書いていた通りのことが起きてたわけですね(T_T)

今後

クローラで収集したデータをJSON化する時に適切な形でエスケープ処理する形で実装しなおし。それがうまくいけば、アプリリリースに向けてかなり前進しそうです