古いバージョンとか新しいバージョンのこと考えてない。
libxml を使ってフィードを取り込む準備にかかろう。
パースするためのコンテクストとしてインスタンス変数を用意する。
- @interface RSSImporter : NSObject {
- // ここ追加
- @private
- xmlParserCtxtPtr context;
- }
- - (void)fromC; // ここ追加(でも、あとで消す)
- @end
パーサ用のコンテクストを作る。←よくわかってない
サーバからデータを受信するごとにパーサに処理させたいのでxmlCreatePushParserCtxt()関数を使う。
xmlCreatePushParserCtxt()の第2引数で任意のデータとしてselfを指定しているのに注目。
通知されるC関数に対して、この任意のデータが引数で渡される。
- // RSSImporter.m の該当箇所を編集すること
- //
- // ここから普通に@implementationです
- //
- @implementation RSSImporter
- /**
- */
- - (id)init {
- self = [super init];
- if (self != nil) {
- // ここを追加
- // パーサ用のコンテクストを作る
- if (!context) {
- context = xmlCreatePushParserCtxt(&simpleSAXHandlerStruct, self, NULL, 0, NULL);
- }
- NSString *feedURL = @"http://eyesrobe.blogspot.com/feeds/posts/default?alt=rss";
- NSURLRequest *requestURL = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURL]];
- NSURLConnection *urlConnection = [[[NSURLConnection alloc] initWithRequest:requestURL delegate:self] autorelease];
- if (urlConnection == nil) {
- NSLog(@"error");
- }
- }
- return self;
- }
- /**
- ちょっとした確認に使う。いらなくなったら消す。
- */
- - (void)fromC {
- NSLog(@"C言語の関数からMethod呼び出せるって不思議");
- }
- - (void)dealloc {
- [super dealloc];
- }
- #pragma mark NSURLConnection Delegate methods
- //
- // ここから下のメソッドが、NSURLConnectionのデリゲートメソッド
- //
- - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
- // データ受信
- NSLog(@"受信中(データは分割されて受信される)");
- // これ追加
- // 受信したデータをパーサに渡している
- // NSDataはC言語では扱えないのでchar型にキャストして渡してる
- xmlParseChunk(context, (const char *)[data bytes], [data length], 0);
- }
- - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
- // 受信完了
- NSLog(@"受信完了");
- // ここを追加
- // パーサを解放
- if (context) {
- xmlFreeParserCtxt(context);
- context = NULL;
- }
- }
- - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
- // 受信エラー
- NSLog(@"エラー");
- // ここを追加
- // パーサを解放
- if (context) {
- xmlFreeParserCtxt(context);
- context = NULL;
- }
- }
- @end
xmlCreatePushParserCtxt()の第2引数で任意のデータとして指定しているselfは、
startElementSAX()やendElementSAX()やcharactersFoundSAX()などのC関数の第1引数で void *context として渡されてる。
イメージとしては、 context == self って感じ。
selfで渡されたデータを処理しやすいように、C関数の中でオブジェクトとして扱える形にすると、C関数の中でObjective-Cなメソッドを呼び出せるようになったり。
こんな感じで。RSSImporter *parserImporter = (RSSImporter *)context;
- // RSSImporter.m の該当箇所を編集すること
- static void startElementSAX(
- void *context,
- const xmlChar *localname,
- const xmlChar *prefix,
- const xmlChar *URI,
- int nb_namespaces,
- const xmlChar **namespaces,
- int nb_attributes, int nb_defaulted,
- const xmlChar **atrributes) {
- // 要素開始の通知を受けたときの処理
- // ここ追加
- // void *context は Objective-C との橋渡し。
- // xmlCreatePushParserCtxt()の第2引数でselfとして渡されたのが、contextとして渡ってきた。
- // 型を合わせることで、Objective-Cのオブジェクトとして扱えるようにしている。
- RSSImporter *paserImporter = (RSSImporter *)context;
- [paserImporter fromC];
- }
ビルドして実行。
続く。