古いバージョンとか新しいバージョンのこと考えてない。
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];
}
ビルドして実行。
続く。