今回からは、RSSリーダを作ってみよう。複数のフィードを登録しておき、それをダウンロードして表示する。技術的には、URLを指定したインターネットリソースのダウンロード、XMLのパース、HTMLの表示などがトピックとなるだろう。
フィードを登録する
まず、購読するRSSフィードの登録を行おう。ここでは、フィードはビルド時に固定としておく。実際に一般ユーザに使ってもらうRSSリーダでは、自由に登録や編集をできるようにすべきだが、今回は省略しておく。
アプリケーションにあらかじめ定められたデータを渡すときは、プロパティリストを使うのが便利だ。プロパティリストはApple特有のデータフォーマットで、XMLをベースとしている。
プロパティリストを使う利点は、開発環境に専用のエディタが付属している事だ。Property List Editorというアプリケーションがある。これを使う事で、グラフィカルにプロパティリストのデータを編集することができる。次の図のように、フィードを記述しておこう。フィードURLの一覧を並べてみた。
プロパティリストを使うときのもう一つの利点は、データの取り込みが簡単な事だ。NSArrayまたはNSDictioanryを使って、メソッドを1つ呼ぶだけでプログラム中で使用可能になる。
先ほどのフィードを、feeds.plistというファイル名で保存し、プロジェクトに追加しておこう。すると、次のようなコードで読み込むことができる。
List 1.
// フィードを取得する
NSString* path;
NSArray* feeds;
path = [[NSBundle mainBundle] pathForResource:@"feeds" ofType:@"plist"];
feeds = [NSArray arrayWithContentsOfFile:path];
まず、NSBundleのpathForResource:ofType:メソッドを使って、feeds.plistファイルのパスを取得する。そして、NSArrayのarrayWithContentsOfFile:メソッドを呼び出すのだ。これだけで、先ほどのフィードのリストがプログラム中でアクセス可能になる。
プロパティリストをどのクラスで読み込むかは、作成するときのルートアイテムのタイプに依存する。ルートのタイプとしてArrayを指定しているならば、NSArrayを使う。Dictionaryの場合は、NSDictionaryだ。
プロパティリストは、非常に扱いやすくて有効な手段だろう。だが、データのサイズが大きいと読み込みにかなり時間がかかってしまう。これは、ファイルをすべて読み込まないとインスタンスとして取り扱えないためだ。サイズが1MBを超えるようであれば、別の手段を検討するようにしたい。
フィードをダウンロードする
続いて、フィードをダウンロードすることを考えよう。URLが得られたので、それが表しているリソースをダウンロードすればいい。
これには、NSURLConnectionというクラスが使える。ネットワーク上のリソースをダウンロードしてくれる、便利なクラスだ。使い方は、まずURLを指定して、NSURLRequestというオブジェクトを作る。それをもとに、NSURLConnectionのインスタンス化を行うのだ。
List 2.
// URLを指定する
NSURLRequest* request;
request = [NSURLRequest requestWithURL:[NSURL URLWithString:feed]];
// URLコネクションを作る
[NSURLConnection connectionWithRequest:_request delegate:self];
これで、すぐにダウンロードが始まる。NSURLConnectionを作るときに、デリゲートを指定することに注意してほしい。ダウンロードしたデータや、終了通知は、デリゲートに送られることになる。
デリゲートメソッドの中で、特に重要なのは次の2つだ。
まず、connection:didReceiveData:。これは、いくばくかのデータがダウンロードされたときに呼び出される。NSURLConnectionによるダウンロードは、すべてのデータが揃ってから通知されるのではなく、ある程度ダウンロードされたところで逐次的にデリゲートを呼び出す。したがって、デリゲート側で、そのデータを1つにまとめて管理しておく必要がある。これには、NSMutableDataをバッファとして作成しておき、そこに追加していけばいい。
List 3.
- (void)connection:(NSURLConnection*)connection
didReceiveData:(NSData*)data
{
// データを追加する
[_data appendData:data];
}
もう1つの重要なメソッドは、connectionDidFinishLoading:だ。これは、すべてのデータのダウンロードが完了したときに呼び出される。これをトリガーとして、データに対する処理を始めることになるだろう。
ダウンロードは非同期で行われる。一応、同期的にダウンロードを行うsendSynchronousRequest:returningResponse:error:というメソッドも用意されてはいる。だが、別スレッドをたてて同期的なダウンロードを行う事は、勧めない。その理由は、一般に複数スレッドを管理するプログラムは複雑になる事、Cocoaではメインスレッド以外から画面描画を行う事は推奨されないので、適時メインスレッドに制御を戻さなくてはいけない事、後述する方法により複数ダウンロードを効率的に行う方法が別に提供されている事、などが挙げられる。
これで、フィードのダウンロードを行う事ができた。だが、RSSリーダでは複数のフィードを同時並行してダウンロードすることが求められる。これを実現する効率的な方法が提供されているので、次回はそれについて説明しよう。