2009/09/16

[Objective-C][iPhone sdk]ajaxを使って、、、

xml(rss)の取得を行い、パースする。
(タイトルが長いので本文にまたがって書きました。)

colormakerのバージョン2を申請しており、その間、次のアプリケーションの構成を練っています。

次は、いよいよ、ネットワーク通信を使ったアプリケーションを作りたいなと思っています。

ネットワーク通信だと、なんだか抽象的ですが、ようは、httpプロトコルのgetメソッドを使ってxml(rss)を取得するということです。

まずは、ポイントを書いてからプログラムをのせたいと思います。

最初のポイントですが、xml(rss)を取得する際、iPhoneのUIつまり、画面(スクリーン)を固めずに取得したいと思います。

これはいまはやりの、ajaxです。
(ajaxのjはjavascriptだが、これは作者がわかりやすいようにつけた名前であり、概念としては、UIをブロックせずに、httpプロトコル通信を行うことであります。)

また、取得するにあたって、
1:http通信を行い、xml(rss)のダウンロードを行う
2:ダウンロードしたxmlを解析し、表示を行う
の2点が重要なポイントとなってきます。

以上をふまえて、実装してみたのですが、ちょっと長いです。
(ご勘弁ください。。。)

プロジェクトの名前は、「Test」です。


/* TestAppDelegate.h */
#import "TestViewController.h"

@interface TestAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;

TestViewController *testviewcontroller;

NSURLConnection *RssConnection;
NSMutableData *RssData;
BOOL appendflg;

}

@property (nonatomic, retain) IBOutlet UIWindow *window;
- (void)parseRSS:(NSData *)data;
@end

/* TestAppDelegate.m */
- (void)applicationDidFinishLaunching:(UIApplication *)application {

testviewcontroller = [[TestViewController alloc] initWithStyle:UITableViewStylePlain];

NSString *feedURLString = @"http://dailynews.yahoo.co.jp/fc/rss.xml";

NSURLRequest *httpRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURLString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0
];

RssConnection = [[NSURLConnection alloc] initWithRequest:httpRequest delegate:self];

/* 接続がうまくいかなかった場合 */
if(RssConnection == nil){
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"エラー"
message:@"接続に失敗しました。"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil
];
[alertView show];
[alertView release];
return;
}

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

[window addSubview:[testviewcontroller view]];
[window makeKeyAndVisible];

}

/* ヘッダー返ってきたとき */
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
/* データの大きさを0で初期化 */
RssData = [[NSMutableData alloc] initWithData:0];
}

/* コンテンツのダウンロードしたとき(完了ではない。連続的にコールされる) */
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
/* データを追加する */
[RssData appendData:data];
}

/* コンテンツのダウンロードエラー */
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

[RssConnection release];
[RssData release];

UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"エラー"
message:@"接続に失敗しました。"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil
];
[alertView show];
[alertView release];

}

/* コンテンツのダウンロードが完了した時 */
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[self parseRSS:RssData];
[RssConnection release];
[RssData release];
}

- (void)parseRSS:(NSData *)data {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

testviewcontroller.parsedData = [NSMutableArray array];

[parser setDelegate:self];
[parser parse];
[pool release];

[testviewcontroller.tableView reloadData];
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if([elementName isEqualToString:@"title"]){
appendflg = YES;
return;
}
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(appendflg == YES){
[testviewcontroller.parsedData addObject:[string stringByReplacingOccurrencesOfString:@"\n" withString:@" "]];
return;
}
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
appendflg = NO;
return;
}


- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {

}

- (void)dealloc {
[RssConnection release];
[RssData release];
[window release];
[super dealloc];
}

/* TestViewController.h */
#import <UIKit/UIKit.h>
@interface TestViewController : UITableViewController {
NSMutableArray *parsedData;
}
@property (nonatomic, retain) NSMutableArray *parsedData;
@end

/* TestViewController.m */
・・・省略・・・
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[[NSNumber alloc] initWithUnsignedInteger:[parsedData count]] integerValue];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}

// Set up the cell...
cell.textLabel.text = [parsedData objectAtIndex:indexPath.row];
return cell;
}
・・・省略・・・

Event-Driven XML Programming Guide for Cocoa
URL Loading System
及び、サンプルコードのSeismicXMLを参考にしながら作ってみました。

SeismicXMLは、マルチスレッドを使って実装されていたのですが、シングルスレッドの方が好きなので、ならべくマルチスレッドを使わずに、実装した結果、上のようになりました。

取得先となったのは、Yahoo.co.jpで公開されているYahoo!ニュース・トピックス - トップなのですが、いざ、実行してみた結果、このような感じになりました。

Photobucket

今回は、時間の都合上、タイトルだけ表示するプログラムなのですが、「Yahoo!ニュース・トピックス - トップ」が、「!」を境に改行を起こしてしまっています。

xmlでは表示されない改行があるのかなーっと思い、配列に追加する時に、置換をかけているのですが、それでも解消されません。

なぜなんだろうなー?

0 コメント:

コメントを投稿