NSXmlParser with UITableView not loading rows
ok so I am trying to parse XML data into a ta开发者_如何学运维ble, this is the code I currently have, it is not showing the name within each row on the table and I think my code is very inefficient because I have read from two different books and tried my best to get everything working together. Please can to suggest code improvements and a fix for my issue thanks :D I am also aware, I havent released anything yet, was going to do that at a later date :)
#import "firstLevelViewController.h"
#define INTERESTING_TAG_NAMES @"text", @"name", nil
@implementation firstLevelViewController
@synthesize tweetsData;
@synthesize userArray;
@synthesize tableArray;
-(void)viewDidLoad
{
self.userArray = [[NSMutableArray alloc] init];
interestingTags = [[NSSet alloc] initWithObjects: INTERESTING_TAG_NAMES];
self.title = @"test";
[tweetsData release];
tweetsData = [[NSMutableData alloc] init]; //alloc the holder for xml, may be large so we use nsmutabledata type
NSURL *url = [NSURL URLWithString:@"http://twitter.com/statuses/public_timeline.xml"];//url string to download
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; //set a request with the url
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; //start the connection and call connection methods from below
[connection release];
[request release];
}
//called various times
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"didReceieveData Connection");
[tweetsData appendData:data]; //append data from method call line to tweetsData tweetsData now holds xml file
}
//called after downloaded finished
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"finished");
[self startParsingTweets];
}
//*****************************START PARSER CODE************************************
-(void)startParsingTweets
{
NSLog(@"parsing init");
NSXMLParser *tweetParser = [[NSXMLParser alloc] initWithData:tweetsData]; //uses the NSMutableData data type to parse
tweetParser.delegate = self; //set the delegate to this viewControlelr
[tweetParser parse];
[tweetParser release];
}
//called when the document is parsed
-(void)parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(@"parsing started");
[tweetsString release]; //make sure its empty to get rid of any previous data
tweetsString = [[NSMutableString alloc] initWithCapacity:(20 * (140 + 20))]; // ( number of calls * ( size of tweet + username )
currentElementName = nil;
currentText = nil;
}
//this is called for each xml element
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
NSLog(@"started element");
if ([elementName isEqualToString:@"status"]) //if elementName == status then start of new tweet so make new dictionary
{
[currentTweetDict release];
currentTweetDict = [[NSMutableDictionary alloc] initWithCapacity:[interestingTags count]]; //make dictionary with two sections
}
else if([interestingTags containsObject:elementName]) //if current element is one stored in interesting tag, hold onto the elementName and make a new string to hold its value
{
currentElementName = elementName; //hold onto current element name
currentText = [[NSMutableString alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(@"appending");
[currentText appendString:string];
}
//after each element it goes back to the parent after calling this method
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:currentElementName])
{
[currentTweetDict setValue: currentText forKey: currentElementName];
}
else if([elementName isEqualToString:@"status"])
{
[self.userArray addObject:currentTweetDict];
//eventually placed in table just testing for now
}
[currentText release];
currentText = nil;
}
-(void)parserDidEndDocument:(NSXMLParser *)parser
{
for(int i=0;i<[self.userArray count];i++)
{
NSDictionary *rowData = [self.userArray objectAtIndex:i];
NSString *textName = [[NSString alloc] initWithFormat:@"user: %@", [rowData objectForKey:@"name"]];
[self.tableArray addObject:textName];
}
NSLog(@"done");
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.userArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *FirstLevelIdentifier = @"FirstLevelIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstLevelIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:FirstLevelIdentifier];
}
NSUInteger row = [indexPath row];
NSDictionary *rowData = [self.tableArray objectAtIndex:row];
NSString *textName = [[NSString alloc] initWithFormat:@"user: %@", [rowData objectForKey:@"name"]];
cell.textLabel.text = textName;
return cell;
}
after your data is ready to be displayed on the table view, you should call reloadData
to make the UITableView
delegate methods be called again.
-(void)parserDidEndDocument:(NSXMLParser *)parser
{
for(int i=0;i<[self.userArray count];i++)
{
NSDictionary *rowData = [self.userArray objectAtIndex:i];
NSString *textName = [[NSString alloc] initWithFormat:@"user: %@", [rowData objectForKey:@"name"]];
[self.tableArray addObject:textName];
}
NSLog(@"done");
//reloadData so that the table view delegate get called again
[self.tableView reloadData];
}
As for the parsing and the async request, it seems you are doing the right way as both NSURLConnection
and NSXMLParser
use the delegation pattern to work.
Some thinks some people might say that you could do to improve performance is replacing NSURLConnection for ASIHttpRequest, and may be use other 3rd party XML library to parse your data faster and easier (here is a nice article about hot to choose the best xml parser for your app)
精彩评论