Titanium Mobile で [UITabBarController setSelectedViewController:] only a view controller in the tab bar controller's list of view controllers can be selected.

Titanium Mobile (Titanium SDK 1.8.2) で
<blockquote class="tr_bq"><div class="p1">[UITabBarController setSelectedViewController:] only a view controller in the tab bar controller’s list of view controllers can be selected.</div></blockquote>という謎のエラーが出た。エラーというか、デバッグメッセージらしい。アプリは問題なく動いている。こういうときは
<blockquote class="tr_bq">tabGroup.setActiveTab(aTab);</blockquote>すれば、メッセージが消える。

厚意を上手に受け取る


<div class="p1">どうしてこの人は、こんなに自分によくしてくれるのだろうか、と思うことが、ときどきある。その厚意は嬉しいけれども、自分よりも他に、もっとそれを受け取るのにふさわしい人がいるのではないか、と。</div><div class="p2">
</div><div class="p1">そういうとき自分は「いえいえ、それは是非○○さんに」と辞退しがちだ。でもこれは、厚意をくれた人のことを考えているわけでもなければ、○○さんのことを考えているわけでもなく、自分のことしか考えていないヒドイ行いだと気づいた。人に譲って、辞退して、いいことをした気になっているだけ。</div><div class="p2">
</div><div class="p1">厚意を差し向けてくれた人は、タイミングとか、いろいろ事情がある中で、その時点では僕がその厚意を受け取るに最も相応しい人だと考えた。ならば、自分は相応しくないからといって辞退するのは単なる逃げで、相手の厚意を無にする行いだ。</div><div class="p2">
</div><div class="p1">ここはひとつ、厚意を真正面から上手に受け取って、相手も自分も喜べるようにしたい。厚意を受け取って、循環させて、さらに大きな厚意が巡り巡ってくるようにしたい。そう思える出来事が今日、あった。感謝。

</div>

applicationDidFinishLaunching: と application:didFinishLaunchingWitnOptions:


<div class="p1">少し古い本を読んでいると、iOS アプリケーションの起動時に UIApplicationDelegate プロトコルの applicationDidFinishLaunching: が呼ばれることになっている。しかし新しい本だと application:didFinishLaunchingWitnOptions: が使われている。</div><div class="p2">
</div><div class="p1">両者は基本的には同じだが、前者が iOS 2.0以降、後者が iOS 3.0以降で使えるメソッドで、いまは後者の利用が強く推奨されている。</div><div class="p1">
</div><div class="p1">Appleのドキュメントにはこう記されている。</div><div class="p2">
</div><blockquote class="tr_bq">applicationDidFinishLaunching:
This method is used in earlier versions of iOS to initialize the application and prepare it to run. In iOS 3.0 and later, you should use theapplication:didFinishLaunchingWithOptions: instead.</blockquote>
<blockquote class="tr_bq">application:didFinishLaunchingWithOptions:
Note: It is highly recommended that you use this method to initialize your application and not the applicationDidFinishLaunching: method.</blockquote><div class="p7">
</div><div class="p1">application:didFinishLaunchingWithOptions: (NSDictionary*) launchOptions には、アプリケーションの起動理由(the reason the application was launched)が入っている。起動理由というのは、他のアプリケーションから openURL: で起動されたときの NSURL や、起動元のアプリケーションの bundle ID だ。なぜこのアプリケーションが起動に至ったのかがわかる。</div><div class="p2">
</div><blockquote class="tr_bq">Launch Options Keys
Keys used to access values in the launch options dictionary passed to the application:didFinishLaunchingWithOptions: method of the application delegate.
NSString *const UIApplicationLaunchOptionsURLKey;
NSString *const UIApplicationLaunchOptionsSourceApplicationKey;
NSString *const UIApplicationLaunchOptionsRemoteNotificationKey;
NSString *const UIApplicationLaunchOptionsAnnotationKey;
NSString *const UIApplicationLaunchOptionsLocalNotificationKey;
NSString *const UIApplicationLaunchOptionsLocationKey;
NSString *const UIApplicationLaunchOptionsNewsstandDownloadsKey;</blockquote><div class="p2">
</div>

Titanium Mobile で OSError: No such file or directory: bad path


<div class="p1">Titanum Mobile 1.8.2 でスマホ向けのアプリを試しているが、Titanium Studio から iPhoneシミュレータを起動すると、2回に1回必ずエラーで止まる。</div><div class="p2">
</div><blockquote class="tr_bq">[INFO] One moment, building …
[INFO] Titanium SDK version: 1.8.2 (02/23/12 17:46 59b3a90)
[INFO] iPhone Device family: universal
[INFO] iPhone SDK version: 5.0
[INFO] iPhone simulated device: iphone
[ERROR] Error: Traceback (most recent call last):
  File “/Users/xxx/Library/Application Support/Titanium/mobilesdk/osx/1.8.2/iphone/builder.py”, line 1310, in main
    cleanup_app_logfiles(ti, log_id, iphone_version)
  File “/Users/xxx/Library/Application Support/Titanium/mobilesdk/osx/1.8.2/iphone/builder.py”, line 534, in cleanup_app_logfiles
    os.remove(i)
OSError: [Errno 2] No such file or directory: ‘bad path 79AFC600-0000-0000-0000-006B00000000’</blockquote><div class="p2">
</div><div class="p1">コードが悪いのかといろいろ変えてみたが症状おさまらず。ググってみたら、開発環境のバグらしい。</div><div class="p2">
</div><div class="p3">http://developer.appcelerator.com/question/131296/crash-every-2nd-time-i-launch</div><div class="p2">
</div><div class="p1">上記エラーメッセージ中に出てくる builder.py を変更したら直った。パス中の空白をバックスラッシュでエスケープする。</div><div class="p4">
</div><div class="p1">変更前</div><blockquote class="tr_bq">simulator_dir = os.path.expanduser(‘~/Library/Application Support/iPhone Simulator/%s’ % iphone_version)</blockquote><div class="p6">
</div><div class="p7">変更後</div><blockquote class="tr_bq">simulator_dir = os.path.expanduser(‘~/Library/Application\ Support/iPhone\ Simulator/%s’ % iphone_version)</blockquote><div class="p5">
</div>

Smarty の math 関数


Smarty の math 関数

Smarty の math で、剰余を得る % 演算子を使いたいなと思ってマニュアルを調べると、

<blockquote class="tr_bq">+, -, /, *, abs, ceil, cos, exp, floor, log, log10, max, min, pi, pow, rand, round, sin, sqrt, srans and tan are all valid operators. Check the PHP documentation for further information on these math functions.</blockquote>
としか書かれていない。四則演算はいいけど % はダメなのかと思ったが、実際にコードを書くと問題なく動く。

そこで math 関数の実装を覗いてみた。
http://smarty-php.googlecode.com/svn/trunk/distribution/libs/plugins/function.math.php

許される関数は
<blockquote class="tr_bq">    static $_allowed_funcs = array(
        ‘int’ => true, ‘abs’ => true, ‘ceil’ => true, ‘cos’ => true, ‘exp’ => true, ‘floor’ => true,
        ‘log’ => true, ‘log10’ => true, ‘max’ => true, ‘min’ => true, ‘pi’ => true, ‘pow’ => true,
        ‘rand’ => true, ‘round’ => true, ‘sin’ => true, ‘sqrt’ => true, ‘srand’ => true ,’tan’ => true
    );</blockquote>と決まっている。

まず丸カッコの個数が合っていることを確認する。

<blockquote class="tr_bq">    if (substr_count($equation,”(“) != substr_count($equation,”)”)) {
        trigger_error(“math: unbalanced parenthesis”,E_USER_WARNING);
        return;
    }</blockquote>
次に equation で渡された数式を要素に分ける。16進数または文字列(変数名または関数名)を探して $match に入れる。

<blockquote class="tr_bq">    preg_match_all(“!(?:0x[a-fA-F0-9]+)
([a-zA-Z][a-zA-Z0-9_]*)!”,$equation, $match);</blockquote>
$match[1] には文字列の配列が入っている。正規表現の (?: により16進数はキャプチャされない。文字列が引数として渡された変数名でもなく、$_allowed_funcs で定義された関数名でもなければエラー。

<blockquote class="tr_bq">    foreach($match[1] as $curr_var) {
        if ($curr_var && !isset($params[$curr_var]) && !isset($_allowed_funcs[$curr_var])) {
            trigger_error(“math: function call $curr_var not allowed”,E_USER_WARNING);
            return;
        }
    }</blockquote>
引数として渡された変数が空ではなく、さらに数値であることを確認する。問題なければ $equation 中の変数を変数値で置き換える。

<blockquote class="tr_bq">    foreach($params as $key => $val) {
        if ($key != “equation” && $key != “format” && $key != “assign”) {
            // make sure value is not empty
            if (strlen($val)==0) {
                trigger_error(“math: parameter $key is empty”,E_USER_WARNING);
                return;
            }
            if (!is_numeric($val)) {
                trigger_error(“math: parameter $key: is not numeric”,E_USER_WARNING);
                return;
            }
            $equation = preg_replace(“/\b$key\b/”, “ $params[‘$key’] “, $equation);
        }
    }</blockquote>
最後に eval() で評価する。

<blockquote class="tr_bq">    $smarty_math_result = null;
    eval(“$smarty_math_result = “.$equation.”;”);</blockquote>
ということで、演算子はチェック対象外なので、なんでも通る、ということがわかった。
<div>
</div>