XMLからオブジェクトのデシリアライズをするiOS用のライブラリ「ChimeraXML(キメラXML)」をgithubに公開しました。
iOSのXMLデシリアライズライブラリ「ChimeraXML」
iOSのXMLデシリアライズライブラリ「ChimeraXML」
Objective-cという言語はとても柔軟でかつ強力な言語であり、またC言語を内包しているため、
C言語で記述されたライブラリを境界なく使用できるという利点もあります。
しかし、不思議なことに、C#やJavaで提供されているXMLシリアライズ/デシリアライズ用のライブラリがなかなか
見つからないのです。
全く無いわけでは無いのですが、一般に広く認知されているライブラリが無いのです。
そのため、前回や前々回の記事で扱ったようにNSXMLParser等を使用してコツコツXMLを処理を書いて
いく事になってしまいます。
そこで本稿から数回に分けて、iOSでXMLからオブジェクトへのデシリアライズを試してみたいと思います。 まずは以下の簡単なXMLを使用します。
<User> <userId>1</userId> <name>山田太郎</name> <email>xxxxx@xxxx.com</email> </User>
このXMLをデシリアライズする先のクラスが以下です。
@interface User : NSObject @property(strong,nonatomic) NSString *userId; @property(strong,nonatomic) NSString *name; @property(strong,nonatomic) NSString *email; @end
まず、デシリアライズを実現するために必要なことを洗い出してみたいと思います。
①Userという文字列からUserクラスのインスタンスが生成する
②XMLをパースしながら、Userクラスのインスタンスのプロパティに値を設定する。
①は、「NSClassFromString」を使用することで簡単に出来ます。
Class userCls = NSClassFromString(@"User"); User *user = [[userCls alloc] init];
②についてもObjective-cには非常に便利な仕組みが提供されています。
XMLをパースする部分は前回の記事で紹介していますので、
ここでは、タグ名とテキストノードの値がとれてからオブジェクトに値を設定する部分について紹介します。
方法は2通りあります。一つ目はKVCを使用する方法です。
[user setValue:@"1" forKey:@"userId"];
KVCが何かという説明はまたどこかでさせて頂くとして、この方法は全ての型のオブジェクトに対して利用することが 可能です。
setValueの後に値を、forKeyの後にプロパティ名を記述するだけです。
ちなみに値の取得は
[user valueForKey:@"userId"]);
になります。 2つ目の方法はperformSelectorを使用する方法です。
if([user respondsToSelector:userIdSEL]){ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [user performSelector:userIdSEL withObject:@"1"]; #pragma clang diagnostic pop }
プロパティのセッターをperformSelectorでコールする方法です。こちらの方法だとセッターが
存在しているか先にチェックすることができますので、今回の用途でいうと②の方が安全だと
思います。(厳密にいうと①でも、keyの存在チェックする方法はありますが、少し面倒なので)
「#pragma・・・」の部分は、「performSelector may cause a leak because its selector is unknown」
というコンパイラ警告がでるのを防止するためのおまじないです。ARCを利用していると、これがでてしまうようです。
さて、ここまでは順調ですね。iPhoneでもXMLのデシリアライズができそうです。
しかし、JavaやC#の経験がある方は既にお気づきかもしれませんが、
Objective-cにはJavaのアノテーションやC#のアトリビュートのようにメタデータを記述する方法が
無いので、要素名とプロパティ名は常に一定のルールに従って、命名しておく必要がでてきます。
例えば本稿のサンプルでは常に要素名とプロパティ名を一致させています。
他にも、例えば要素名にハイフンが入っている場合は、プロパティ名をキャメル形式にしておくとか
あるかもしれませんね。
ただ、サーバーサイドを自分たちで開発している場合は良いのですが、サードパーティのAPIを 使用する場合、これではかなり使いにくいですね。
これを解決するために、デシリアライズ先となるオブジェクトに共通の親クラスを設けて、
要素名に対応するプロパティ名を問い合わせすることができる仕組み(メソッドを設ける)を考えてみました。
長くなってきたので、それについては次回の記事で詳しくご紹介します。
iOSでXMLからデシリアライズする(1) - 準備編
iOSでXMLからデシリアライズする(2) - アノテーションの代替を考える
iOSでXMLからデシリアライズする(3) - 単純なXMLを扱う
iOSでXMLからデシリアライズする(4) - 不要な要素を無視する
iOSでXMLからデシリアライズする(5) - コレクション要素を扱う
iOSでXMLからデシリアライズする(2) - アノテーションの代替を考える
iOSでXMLからデシリアライズする(3) - 単純なXMLを扱う
iOSでXMLからデシリアライズする(4) - 不要な要素を無視する
iOSでXMLからデシリアライズする(5) - コレクション要素を扱う
コメント
コメントの投稿
トラックバック
http://csfun.blog49.fc2.com/tb.php/114-ae856215