Reputation: 3671
this question might sound silly but I cant seem to get the idea of asynchronous downloading, parsing and displaying the data. There are a lot of articles about asynchronous parsing and I have read a lot of them, but I didn't find any article about correctly displaying the asynchronously downloaded data. I have an application that uses a parser to parse a rss feed. At first I used a synchronous request and everything worked well even though the app lagged a little while waiting for the data (obviously). The xml parser looks like this:
#import "XMLAsynchronousParser.h"
@implementation XMLAsynchronousParser
@synthesize itemList;
-(void)startParse:(NSString *)url{
parsing = YES;
receivedData = [[NSMutableData alloc] init];
itemList = [[NSMutableArray alloc] init];
errorParsing = NO;
NSLog(@"PARSING from url:\n%@",url);
NSString *agentString = @"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setValue:agentString forHTTPHeaderField:@"User-Agent"];
NSURLConnection *urlConnection = [NSURLConnection connectionWithRequest:request delegate:self];
[urlConnection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(@"Connection did finish loading");
rssParser = [[NSXMLParser alloc] initWithData:receivedData];
[rssParser setDelegate:self];
[rssParser parse];
parsing = NO;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@"Asynchronous parsing did end with error:\n%@",[error description]);
}
#pragma Mark - parsing methods
- (void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(@"FILE found and parsing started.");
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
elementValue = [[NSMutableString alloc] init];
if([currentElement isEqualToString:@"item"]){
item = [[NSMutableDictionary alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if([elementName isEqualToString:@"item"]){
[itemList addObject:[item copy]];
}else{
[item setObject:elementValue forKey:elementName];
}
}
@end
I am initializing the parser in the awakefromnib
method like this:self.xmlParser = [[XMLAsynchronousParser alloc] init];
Calling the start parse method after refreshing:
- (void)dropViewDidBeginRefreshing{
NSArray *filters = [[NSArray alloc] init];
NSMutableArray *itemList = [[NSMutableArray alloc] init];
filters = [self.dataController selectSelectedFilters];
for (BazosAgentFilter *filter in filters) {
NSString *url = [self.dataController createURLfromFilter:filter];
[self.xmlParser startParse:url];
for (NSDictionary *item in self.xmlParser.itemList) {
NSString *title = [item objectForKey:@"title"];
NSString *description = [item objectForKey:@"description"];
NSString *pubdate = [item objectForKey:@"pubDate"];
NSString *link = [item objectForKey:@"link"];
BazosAgentItem *bazosItem = [[BazosAgentItem alloc] initWithTitle:title
description:description
link:link
pubdate:pubdate
filterId:filter.filter_id];
[self.dataController addBazosAgentItem:bazosItem];
}
[itemList addObjectsFromArray:[self.dataController selectItemsFromDatabaseWithFilterId:[filter.filter_id integerValue]]];
}
self.itemList = itemList;
[self.tableView reloadData];
[self.refreshControl endRefreshing];
}
and the cellForRowAtIndexPath
method looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"###cell for row!");
NSString *cellIdentifier = @"BazosItemCell";
ItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
BazosAgentItem *item = [self.itemList objectAtIndex:indexPath.row];
NSLog(@"ITEM LINK: %@",item.link);
NSString *itemTitle = item.title;
NSString *itemID = [self parseItemID:item.link];
NSString *itemIDpostfix = [itemID substringFromIndex:(itemID.length-3)];
NSString *itemImageString = [NSString stringWithFormat:@"http://www.bazos.sk/img/1/%@/%@.jpg",itemIDpostfix,itemID];
NSURL *itemImageUrl = [NSURL URLWithString:itemImageString];
[cell.itemImage setImageWithURL:itemImageUrl];
cell.itemImage.contentMode = UIViewContentModeScaleAspectFit;
cell.firstLabel.text = itemTitle;
[cell sizeToFit];
return cell;
}
The thing is, that the UITableView doesnt show anything after I use the Refresh method. Am I missing something?
Upvotes: 0
Views: 493
Reputation: 41642
I did not read all your code, but in general the proper solution is as follows.
1) when you have complete chunks of data, dispatch a block to,the main thread with it. Ask the table for its visible cells, and if the data would change any of them, then update your data model (most likely a mutable array), then reload the table.
2) if the data would not be visible just store it in the array. When the user scrolls the table you can use the data then.
Upvotes: 2