2010年9月30日木曜日

Objective-C + libxml2 を使ってフィードを取り込みたいんだ (3)

Xcode 3.2.4 and iOS SDK 4.1 で試してる。
古いバージョンとか新しいバージョンのこと考えてない。

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];
}



ビルドして実行。

続く。

0 件のコメント:

コメントを投稿