2008年12月6日土曜日

iPhone開発関係の小ネタ

HTTPプロトコルでのGET/POSTメソッドを用いたkey=value形式のデータの送信時においては、value部分に含まれる特殊文字などを正しく通知するためにURLエンコーディングをする必要があります。空白(0x20)を'+'に置き換えるほかに、URL上許されない文字については16進表記(%XX)にする必要があります。

iPhoneおよびMac OSのフレームワークの文字列クラスであるNSStringクラスには、下記のようなURLエンコード用の関数があるけれど、value要素のエンコーディング目的で利用するのは間違い。


-(NSString *)stringByAddingPercentEscapesUsingEncoding:
(NSStringEncoding)encoding


URLで許容されている文字には&も含まれているため、(GETメソッドを思い出してもらえばわかる通り、URLパスに"key1=value1&key2=value2..."というように&記号が出現することが許されているため、&についてはエンコードされず、value中に&が出現する場合には、key=valueペアの区切りと誤認識してしまう。

この問題を対処するために、stringByAddingPercentEscapesUsingEncodingを呼び出し後に&文字を置き換えるなどの操作をするなどの例もよく見られるようだが、類似の関数としてCore FoundationにCFURLCreateStringByAddingPercentEscapesという関数があるので、value要素のエンコーディングにはこちらを使うほうがすっきりする。


CFStringRef CFURLCreateStringByAddingPercentEscapes (
CFAllocatorRef allocator,
CFStringRef originalString,
CFStringRef charactersToLeaveUnescaped,
CFStringRef legalURLCharactersToBeEscaped,
CFStringEncoding encoding
);


幸いCFStringRefとNSStringはTFB(Toll Free Bridge)なので、型のキャストで受け渡しが可能。
legalURLCharactersToBeEscapedにURL文字列としては許容されているけれどValueのエンコーディング時には%XXエンコードしたい文字を文字列として複数指定することによって期待する結果を得ることができる。
もちろん、日本語などのマルチマバイト文字はUTF8などあらかじめ文字コードを変換した上で上記エンコード処理を行う。

データのポスト時に、key=value形式ではなく、XMLなどで構造化したデータを送信する場合には、要素の値には、'<'、'&'、'>'、属性値には、加えてシングルクォート'''やダブルクォート'"'を直接記述することができないので、文字実体参照に置き換える必要がある。
具体的には、


'<' → '&lt;' '&' → '&amp;' '>' → '&gt;'
'\'' → '&apos;'
'\"' → '&quot;'
と、する。MacOS X/iPhoneではそのものズバリのCFXMLCreateStringByUnescapingEntitiesという関数があるが、少なくともMac OS X 10.3.5までは、動作にバグがあるようだ。
最新のLeopardやiPhone OSではどうなのかは未確認。

Google謹製のMac向けのコードライブラリ、Google Toolbox for Macの中には、対策版としてGTMNSString+XML.h/mがあるので、こちらを使う方が良さそう。
ちなみに、上記key=valueパラメータのエンコーディングについては、NSDictionary型から変換するためのクラスGTMNSDictionary+URLArguments.h/mがあるので、もう少しスマートに記述できる。
Google Toolbox for Macについては、Apache License 2.0なので、比較的自由に利用できる。
iPhoneでの利用も可能なので、Google Toolbox for Macについては、あれこれ内容を見てみるつもり。
必要だと思ったコードが既にあるという意味ではとてもありがたい。Google恐るべし。

0 件のコメント: