Mac OS X wi-fi tips

Mac OSではネットワークの設定はLocationという単位で切り替えることができます。
terminalからは /usr/sbin/scselect コマンドで現在の設定を確認できます。

$ scselect

  xxxxxxxx-44F6-4EFE-BE5C-B5E0B91B7CDC (foo)
* xxxxxxxx-1D83-4E30-A533-77C2CE1E59EA (Automatic)
  xxxxxxxx-FAE4-4D87-9014-D1012E0807A5 (bar)

scselectコマンドの後にLocation名を書くとその設定に切り替わります。
自分は頻繁に切り替えるのでエイリアスを設定しておきました。

$ echo 'ailas foo-net="scselect foo"' >> ~/.bashrc

またwi-fiの調子が悪い時はAirMacのON-OFFを繰り返すとたまに改善することがあるので、
これもエイリアスに登録しておきます。
AirMacの操作は /usr/sbin/networksetup コマンドを使うと可能です。

$ echo 'alias wifi="networksetup -setairportpower en0"' >> ~/.bashrc
# en0はMacBookの場合です。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ wifi on  # AirMac起動
$ wifi off # AirMac停止

【iOS】バックグラウンドでBluetoothのコネクションを維持する

iOSデバイスでのBluetooth通信は基本アプリが画面内に表示されている'フォアグラウンド'の時のみ有効です。
今回はアプリがバックグラウンドに隠れた間でも、Bluetooth通信を可能にする裏技的な(?)tipsを紹介します。

バックグラウンドで実行可能な処理

まずiOSでバックグラウンド実行が可能なものを見てみましょう。
iOSでは、バックグラウンドで行える処理が以下のものに限られています。
Apple iOS App Programming Guide

  • 音楽の再生
  • 位置情報の取得
  • VoIP
  • Newsstandを使用するアプリ
  • 外部アクセサリから定期的に情報をアップデートするアプリ

このような、バックグラウンドでの動作が重要なサービスに限り許されています。

iOS Bluetoothフレームワークの種類

iOSが提供するBluetoothフレームワークには大きく分けて2種類あります。

名称 使用可能なデバイス バックグラウンド通信
Game Kit Bluetoothが使用可能なiPhone全て ×
Core Bluetooth iPhone4S以降

CoreBluetoothはBluetooth LE(Low Energy)に対応した外部機器との通信のみに使われます。
今回のターゲットはGame Kitフレームワークでのバックグラウンド通信です。

Bluetoothのコネクションを維持する方法

ではバックグラウンド通信を可能にするにはどうしたらいいのでしょうか。
実は、音楽をバックグラウンドで再生している間は、Bluetoothの通信が可能となっています。

以下、無音の音楽を永遠と再生し続けるサンプルコードです。

    // オーディオデータフォーマットを表す構造体を作成
    AudioStreamBasicDescription dummyASBD;
    dummyASBD.mSampleRate = 44100.0;
    dummyASBD.mFormatID = kAudioFormatLinearPCM;
    dummyASBD.mFormatFlags = kAudioFormatFlagsCanonical;
    dummyASBD.mBytesPerPacket = 4;
    dummyASBD.mFramesPerPacket = 1;
    dummyASBD.mBytesPerFrame = 4;
    dummyASBD.mChannelsPerFrame = 2;
    dummyASBD.mBitsPerChannel = 16;
    dummyASBD.mReserved = 0;
    
    OSStatus status;
    // AudioQueueの作成
    status = AudioQueueNewOutput(&dummyASBD,
                                 dummyAudioQueueCallBack,
                                 self,
                                 NULL,
                                 NULL,
                                 0,
                                 &dummyAudioQueue);
    if (status) {
        NSLog("error @AudioQueueNewOutput");
    }
    
    // 再生
    status = AudioQueueStart(dummyAudioQueue, NULL);
    if (status) {
        NSLog(@"error @AudioQueueStart");
    }

実際にバックグラウンドで試すときは、アプリのinfo.plistのバックグラウンドモードの項目にAudio Playが設定されていることを確かめてください。

<key>UIBackgroundModes</key> 
<array>
    <string>audio</string>
</array>

この状態であれば、GKSessionクラスのsendDataToAllPeers:withDataMode:error:メソッドや、receiveData:fromPeer:inSession:context:メソッドでデータの送受信が可能となっています。

最後に

もしかすると、音楽の再生以外にもバックグラウンド処理が許されているもの(例えばVoIPなど)でも同じことが可能かもしれません。
尚、この方法はAppleのガイドラインには書かれていないため、明らかに不推奨な方法だと思われます。 バックグラウンドで通信することに意義があるサービスのみに適応するよう心がけてください。

template engine embedded in underscore.js

クライアントサイドのテンプレートエンジンはjQueryのものが有名ですが、 今回はUnderscore.jsに備わっているミニマムなテンプレートエンジンの使い方を紹介します。 Underscore.jsは、クライアントMVCの代表格の1つであるBackbone.jsで採用されている便利ライブラリです。 (ちなみに両ライブラリの作者はCoffeeScriptを開発しているbraddunbarだったりします。)

この記事はUnderscore.js ver1.4.3を元に記載しています。

テンプレートの構文

Underscore.jsのテンプレートの区切り文字(delimiter)はデフォルトではERB-styleです。 区切り文字を変更するには、_.templateSettingsというオブジェクトの各プロパティ(evaluate, interpolate, escape)を変更することで可能です。

  • 評価
    • コードをテンプレートの中で評価したい場合は、<% %>で括ります。
  • 埋め込み
    • 変数などを評価してHTMLに埋め込みたい場合、<%= %>で括ります。
  • エスケープ
    • HTML文字としてエスケープする場合は、<%- %>で括ります。

例)

// テンプレート実行前
<% for (var i = 0; i < 3; i++) { %>
    <p>Hello <%= i+1 %> Underscore!</p>
<% } %>

// テンプレート実行後
    <p>Hello 1 Underscore!</p>
    <p>Hello 2 Underscore!</p>
    <p>Hello 3 Underscore!</p>

HTML内での使い方

実際にテンプレートを使用してみましょう。 HTML内にインラインでテンプレートを記述する場合は<script>タグを使用し、HTMLとして画面に出力されないようにします。
そしてテンプレートの部分を文字列として取得し、それを_.template()関数に入れ、テンプレートをプリコンパイルします。
プリコンパイルした結果は関数となっており、その関数を実行することで最終的なHTML文字列が得られます。
また、プリコンパイルした関数は引数としてオブジェクトを渡すことができ、テンプレート内ではそのプロパティ名でアクセス可能です。

元HTMLコード

<html>
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.3/underscore-min.js"></script>
</head>
<body>
    <div id="target"></div>

    <!-- テンプレート -->
    <script type="text/html" id="target_template">
        <% for (var i = 0; i < 3; i++) { %>
            <p>Hello <%= foo %>! <%= bar %>!</p>
        <% } %>
    </script>

    <script>
        // テンプレートを文字列として取得
        var $templateString = $('#target_template').html();
        // テンプレートをコンパイルし、テンプレート関数を得る
        var template = _.template($templateString);
        // テンプレート関数を実行
        var html = template({
            foo: 'foo',
            bar: 'bar'
        });
        // 
        $('#target').html(html);
    </script>
</body>
</html>

ブラウザで見るとJavaScriptが解釈され、このように表示されます。

Hello foo! bar!

Hello foo! bar!

Hello foo! bar!

Underscore.jsでのテンプレートの実装

使い方は非常に簡単でした。 さて、実装はどうなっているのでしょうか。 underscore.jsはコードサイズも小さくまとまっているため、実装を追いやすく、JavaScriptのコードリーディングにも最適です。

テンプレート部分のコードを転載します。

_.template = function(text, data, settings) {
  var render;
  settings = _.defaults({}, settings, _.templateSettings);

  // Combine delimiters into one regular expression via alternation.
  var matcher = new RegExp([
    (settings.escape || noMatch).source,
    (settings.interpolate || noMatch).source,
    (settings.evaluate || noMatch).source
  ].join('|') + '|$', 'g');

  // Compile the template source, escaping string literals appropriately.
  var index = 0;
  var source = "__p+='";
  text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
    source += text.slice(index, offset)
      .replace(escaper, function(match) { return '¥¥' + escapes[match]; });

    if (escape) {
      source += "'+¥n((__t=(" + escape + "))==null?'':_.escape(__t))+¥n'";
    }
    if (interpolate) {
      source += "'+¥n((__t=(" + interpolate + "))==null?'':__t)+¥n'";
    }
    if (evaluate) {
      source += "';¥n" + evaluate + "¥n__p+='";
    }
    index = offset + match.length;
    return match;
  });
  source += "';¥n";

  // If a variable is not specified, place data values in local scope.
  if (!settings.variable) source = 'with(obj||{}){¥n' + source + '}¥n';

  source = "var __t,__p='',__j=Array.prototype.join," +
    "print=function(){__p+=__j.call(arguments,'');};¥n" +
    source + "return __p;¥n";

  try {
    render = new Function(settings.variable || 'obj', '_', source);
  } catch (e) {
    e.source = source;
    throw e;
  }

  if (data) return render(data, _);
  var template = function(data) {
    return render.call(this, data, _);
  };

  // Provide the compiled function source as a convenience for precompilation.
  template.source = 'function(' + (settings.variable || 'obj') + '){¥n' + source + '}';

  return template;
};

まず、matcherという変数が定義されています。 このmatcherはテンプレート構文に従った正規表現オブジェクトになっています。
そしてこの関数に渡されたテンプレート文字列textを、text.replaceでテンプレート構文にマッチする箇所を探し出します。 replace関数にfunctionを渡すと、マッチする箇所が見つかるたびにその関数が呼び出されます。ここでのreplace関数の使い方は元のtextを変更するのではなく、変数sourceに文字列を付け足していく処理を行なっています。
replace関数に渡されたfunctionの中は、

  • escape(エスケープ)構文が見つかった場合
    • '+\n ( (__t=(foo) ) == null ? '' : _.escape(__t) )+\n'
      
  • interpolate(埋め込み)構文が見つかった場合
    • '+\n ( (__t=(bar) ) == null ? '' : __t)+\n'
      
  • evaluate(評価)構文が見つかった場合
    • ';\n var i = 0; \n __p+='`
      

で場合分けされ、対応する文字列が変数sourceに付け加えられます。
何をやっているのかよくわかりませんね。実際に実行した時の変数sourceの中身を見てみましょう。 (Chromeのデバッガを使うと便利です。)

<% for (var i = 0; i < 3; i++) { %>
    <p>Hello <%= foo %></p>
<% } %>

上記のようなテンプレート文字列があったとき、text.replaceを通過したあとの変数sourceは以下のような文字列になっています。

source = "__p+='\n';for (var i = 0; i < 3; i++) { __p+='\n<p>Hello '+((__t=( foo ))==null?'':__t)+'!</p>\n';} __p+='\n';\n"

なにやら、__pという変数に文字列を付け加えていく処理を表す文字列のようです。

最終的にこのsourceは、Functionコンストラクタを介して関数オブジェクトへと変わります。以下、動的に作られた関数renderの内容です。

function render (obj, _) {
  var __t,
      __p = '',
      __j = Array.prototype.join,
      print = function () { __p += __j.call(arguments, ''); };
  with (obj || {}) {
    __p+='\n        ';
    for (var i = 0; i < 3; i++) { 
      __p+='\n           <p>Hello '+
      ((__t=( foo ))==null?'':__t)+
      '!</p> \n        ';
    } 
    __p+='\n    ';
  }
  return __p;
}

これでやっていることは明確になりました。
__pはテンプレート関数の実行結果であるHTML文字列を表します。 またwith文で実行時のコンテキストがobjになるため、引数で渡されたオブジェクトのプロパティにアクセスする際に、オブジェクト名をつけずに(obj.foo)、プロパティ名そのもの(foo)でアクセスできます。 (もしオブジェクト名を付けなければいけないとすると、必ず'obj'という固定の仮引数名をテンプレートの中で使わなくてはいけなく、柔軟性に欠けます。)

この_.template()関数の最終的な返り値は、動的に作ったrender関数を呼ぶ関数になります。

  var template = function(data) {
    return render.call(this, data, _);
  };
  return template;

まとめ

Underscore.jsのテンプレートエンジンの使い方と実装を見てみました。
Backbone.jsと対に使われるUnderscore.jsですが、単体で見てもこのテンプレート機能以外にも面白い(特に関数型言語のような)関数が豊富に用意されているので、皆さんも是非使って、そして実装を追ってみてください。

iPod共有アプリ「 Listen with」リリース!

新しいiPhoneアプリListen with」をリリースしました!

このアプリは自分のiPhoneに入っている曲を他の人のiPhone上でも、
同時に一緒に 聴くことができるアプリです。

Bluetoothを使ってiPhoneの曲をもう一方のiPhoneにストリーミングするため、
地下鉄などの電波のない環境でも使用できます。

アプリのデザインに関しては、このアプリのデザイナーである@Haeyoung_SさんのHPで見ることができます。
http://vividviolethy.wordpress.com/

次回から、このアプリを作る上で技術的に困難だったことを紹介したいと思います。
具体的には、

といったあたりです。


是非お友達と一緒に使ってみてください!

Listen withはApp Storeから無料でダウンロードできます。

Listen with - Yuuki Furuyama

Phrase Mania - ver2.0.0をリリース

iPhoneアプリPhrase Mania」を先日ver2.0.0にアップデートしました。

以前から「耳コピをしやすくしてほしい」という意見がありましたので、ver2.0.0の新機能として「耳コピモード」という新しいモードを追加しました。


耳コピモードでは
1. リピート区間を設定してその部分を繰り返し再生したり
2. 特定の秒数(1秒〜15秒)、もしくは設定したリピートの先頭場所に瞬時に巻き戻したりすることができます。

もちろん速度調節も組み合わせて使えますので、原曲の半分のテンポで同じ箇所を繰り返し再生したり、なんてことが可能です。

耳コピモードは、再生画面上部の「PHRASE・SONG・COPY」という文字をタップすることで切り替えられます。是非使ってみてください。

次のバージョンに向けてご要望などございましたら、お気軽にコメント欄からどうぞ!

Phrase Mania - Yuuki Furuyama

Xcode4.2 β版からXcode4.0.2に戻した時に起きるCode Sign Error対処法

アプリのアップデート版が完成したので、App Store用にアプリをアーカイブしようとするとこのような警告が出て一向に進みませんでした。

Application failed codesign verification. The signature was invalid, or it was not signed with an Apple submission certificate. (-19011)

このエラーが出た原因として考えられることは、

・Release用のProvisioning ProfileがDistributionになっていない
・Distribution用の証明書を取得していない
・上2つの有効期限が切れている

など、証明書やProvisioning Profile周りの原因が多いのですが、今回はその全てにも当てはまりません。
まさかXcode4.2からXcode4.0.2に戻したことに何か原因があるのかと思っていたら、まさしくその通りでした。


調べたところ、
Xcode4.2をAppleが薦めているアンインストール方法(ターミナルからアンインストールのスクリプトを実行する方法)でアンインストールすると、Developerディレクトリはそのまま残ってしまいます。そこにXcode4.0.2を新たに入れると、なんとXcode4.0.2を使っているのにもかかわらず、その中で一部のXcode4.2のツールを参照し続けてしまうみたいです。

解決方法としては、ターミナルで

mv /Developer /Developer.old

として、Developerディレクトリを別に移しておいてから、新たにXcode4.0.2をインストールし直すとうまくいきました。

iPhoneアプリ「Phrase Mania Lite」をリリース!!

お待たせしました、iPhoneアプリPhrase Mania」の無料版「Phrase Mania Lite」を本日リリースしました!

有料版との違いは

・再生速度を落として再生することはできない
・フレーズをAAC形式の曲として書き出すことができない

の2点だけです。


是非お試しください!

Phrase Mania Liteはこちらからダウンロード出来ます。
Phrase Mania - Yuuki Furuyama