UITableView crashes when trying to scroll - iphone

I have a problem with data in UITableView. I have UIViewController, that contains UITableView outlet and few more things I am using and ... It works :) ... it works lovely, but ...
I've created an RSS reader class that is using delegates to deploy the data to the table ... and once again, If I'll just create dummy data in the main controller everything works!
problem is with this line: rss.delegate = self;
Preview looks a little bit broken than here are those RSS reader files on Google code:
(Link to the header file on GoogleCode)
(Link to the implementation file on Google code)
viewDidLoad function of my controller:
IGDataRss20 *rss = [[[IGDataRss20 alloc] init] autorelease];
rss.delegate = self;
[rss initWithContentsOfUrl:#"http://rss.cnn.com/rss/cnn_topstories.rss"];
and my delegate methods:
- (void)parsingEnded:(NSArray *)result {
super.data = [[NSMutableArray alloc] initWithArray:result];
NSLog(#"My Items: %d", [super.data count]);
[super.table reloadData];
NSLog(#"Parsing ended");
}
- (void)parsingError:(NSString *)message {
NSLog(#"MyMessage: %#", message);
}
- (void)parsingStarted:(NSXMLParser *)parser {
NSLog(#"Parsing started");
}
Just to clarify, NSLog(#"Parsing ended"); is being executed and I have 10 items in the array.
Hope someone will be able to help me as I am becoming to be quite desperate, and I thought I am not already such a greenhorn :)
Thanks,
Ondrej
Full copy of my header file (table controller)
the WGTempTableController class is UIViewController with table outlet, data array etc ...
//
// CRFeedController.h
// czReader
//
// Created by Ondrej Rafaj on 5.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "WGTempTableController.h"
#import <IGDataRss20.h>
#interface CRFeedController : WGTempTableController <IGDataRss20Delegate> {
//NSString *startUrl;
}
#end
Full copy of my implementation file (table controller)
All other functions like numberOfSectionsInTableView or numberOfRowsInSection are in that WGTempTableController
//
// CRFeedController.m
// czReader
//
// Created by Ondrej Rafaj on 5.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import "CRFeedController.h"
#import "WGTempCell.h"
#implementation CRFeedController
- (void)viewDidLoad {
[super viewDidLoad];
IGDataRss20 *rss = [[[IGDataRss20 alloc] init] autorelease];
rss.delegate = self;
[rss initWithContentsOfUrl:#"http://rss.cnn.com/rss/cnn_topstories.rss"];
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)parsingEnded:(NSArray *)result {
super.data = [[NSMutableArray alloc] initWithArray:result];
NSLog(#"My Items: %d", [super.data count]);
[super.table reloadData];
NSLog(#"Parsing ended");
}
- (void)parsingError:(NSString *)message {
NSLog(#"MyMessage: %#", message);
}
- (void)parsingStarted:(NSXMLParser *)parser {
NSLog(#"Parsing started");
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#pragma mark Table view
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"MyCell";
WGTempCell *cell = (WGTempCell *) [table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CRFeedCell" owner:nil options:nil];
for(id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[WGTempCell class]]) {
cell = (WGTempCell *) currentObject;
break;
}
}
}
NSDictionary *d = [super.data objectAtIndex:indexPath.row];
[[cell cellTitle] setText:[d objectForKey:#"title"]];
return cell;
}
- (void)dealloc {
[super dealloc];
}
#end
Full copy of my header file (rss reader)
//
// IGDataRss20.h
// IGFrameworkProject
//
// Created by Ondrej Rafaj on 4.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import <Foundation/Foundation.h>
#class IGDataRss20;
#protocol IGDataRss20Delegate <NSObject>
#optional
- (void)parsingStarted:(NSXMLParser *)parser;
- (void)parsingError:(NSString *)message;
- (void)parsingEnded:(NSArray *)result;
#end
#interface IGDataRss20 : NSObject {
NSXMLParser *rssParser;
NSMutableArray *data;
NSMutableDictionary *currentItem;
NSString *currentElement;
id <IGDataRss20Delegate> delegate;
}
#property (nonatomic, retain) NSMutableArray *data;
#property (nonatomic, assign) id <IGDataRss20Delegate> delegate;
- (void)initWithContentsOfUrl:(NSString *)rssUrl;
- (void)initWithContentsOfData:(NSData *)inputData;
#end
Full copy of my implementation file (rss reader)
//
// IGDataRss20.m
// IGFrameworkProject
//
// Created by Ondrej Rafaj on 4.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import "IGDataRss20.h"
#implementation IGDataRss20
#synthesize data, delegate;
- (void)initWithContentsOfUrl:(NSString *)rssUrl {
self.data = [[NSMutableArray alloc] init];
NSURL *xmlURL = [NSURL URLWithString:rssUrl];
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[rssParser setDelegate:self];
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)initWithContentsOfData:(NSData *)inputData {
self.data = [[NSMutableArray alloc] init];
rssParser = [[NSXMLParser alloc] initWithData:inputData];
[rssParser setDelegate:self];
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser {
[[self delegate] parsingStarted:parser];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to parse RSS feed (Error code %i )", [parseError code]];
NSLog(#"Error parsing XML: %#", errorString);
if ([parseError code] == 31) NSLog(#"Error code 31 is usually caused by encoding problem.");
[[self delegate] parsingError:errorString];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) currentItem = [[NSMutableDictionary alloc] init];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"item"]) {
[data addObject:(NSDictionary *)[currentItem copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (![currentItem objectForKey:currentElement]) [currentItem setObject:[[[NSMutableString alloc] init] autorelease] forKey:currentElement];
[[currentItem objectForKey:currentElement] appendString:string];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
//NSLog(#"RSS array has %d items: %#", [data count], data);
[[self delegate] parsingEnded:(NSArray *)self.data];
}
- (void)dealloc {
[data, delegate release];
[super dealloc];
}
#end

Your subject says it crashes when you try to scroll. I don't know what this would have to do with your rss.delegate, so I'm just going to ignore that and focus on probable scrolling-related bugs here, which are usually in tableView:cellForRowAtIndexPath:.
Check your CRFeedCell.xib, view info on your WGTempCell object, and make sure its Identifier field matches your CellIdentifier in your code. ("MyCell")
Make sure you're not using that same CellIdentifier for some other UITableViewCell subclass elsewhere in your code.
What kind of crash is it? If it's EXC_BAD_ACCESS, double-click on your executable, go to Arguments, create an NSZombieEnabled environment variable, and set it to YES. (Uncheck it when you're done debugging to avoid leaking memory.) This will show you which object you were trying to access when the app crashed.
Set a breakpoint on the setText: call in tableView:cellForRowAtIndexPath:. Then at your gdb prompt, type po [d objectForKey:#"title"]. Make sure that object is really an NSString.

It looks to me, as if you initialize the NSMutableArray data twice: First in initWithContentsOfUrl: , then again in parsingEnded: . Maybe you should do a removeAllObjects in parsingEnded instead.

Related

How do I add UISearchBar to this?

I want to add a UISearchBarto the following code below, that I am using in Xcode 4.6.
Can someone please help me?
//
#import "SocialMasterViewController.h"
#import "SocialDetailViewController.h"
#interface SocialMasterViewController () {
NSXMLParser *parser;
NSMutableArray *feeds;
NSMutableDictionary *item;
NSMutableString *title;
NSMutableString *link;
NSString *element;
NSArray *filteredStrings;
}
#end
#implementation SocialMasterViewController
-(void)gotosharing {
UIStoryboard *sharingStoryboard = [UIStoryboard storyboardWithName:#"Sharing" bundle:nil];
UIViewController *initialSharingVC = [sharingStoryboard instantiateInitialViewController];
initialSharingVC.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:initialSharingVC animated:YES completion:nil];
}
- (void)awakeFromNib
{
[super awakeFromNib];
}
- (void)viewDidLoad {
[super viewDidLoad];
feeds = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:#"http://www.rssmix.com/u/3735817/rss.xml"
];
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
}
- (void)refresh:(UIRefreshControl *)refreshControl {
[refreshControl endRefreshing];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return feeds.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [[feeds objectAtIndex:indexPath.row] objectForKey: #"title"];
return cell;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
title = [[NSMutableString alloc] init];
link = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[feeds addObject:[item copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([element isEqualToString:#"title"]) {
[title appendString:string];
} else if ([element isEqualToString:#"link"]) {
[link appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self.tableView reloadData];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *string = [feeds[indexPath.row] objectForKey: #"link"];
[[segue destinationViewController] setUrl:string];
}
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self filterURLsWithSearchBar:searchText];
[self.tableView reloadData];
}
- (void)filterURLsWithSearchBar:(NSString *)searchText
{
//[filteredStrings removeAllObjects];
for (NSString *rssUrl in feeds)
{
NSComparisonResult result = [rssUrl compare:searchText
options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)
range:[rssUrl rangeOfString:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)]];
if (result == NSOrderedSame) {
[self->feeds addObject:filteredStrings];
}
}
}
#end
Basically, I am want to filter the results of what is brought in by the NSXMLParser into search terms as they are typed into a search bar.
Any help is much appreciated from you guys/gals.
Do this
Store the value get from parser into an array. responseArray
Use another array to store the value to show in table
datasourceArray
After webvservice recieve successful response datasourceArray=responseArray then reload table with [tableView reloadData]
When search starts,search from responseArray load the result into DatasourceArray then call reloadData again
you can use textFeildDidBegunEditingdelegate method of uitextFeild
then this code will help you filter
NSMutableArray *array1=(NSMutableArray*)[txtEditFavoriteColor.text componentsSeparatedByString:#" "];//words from textFeild
for (NSString *str in array1)
{
NSString *tempStr = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if([tempStr length])
{
[arryOfWordsToBeSearched addObject:tempStr];
}
}
NSMutableArray *subpredicates = [NSMutableArray array];
for(NSString *term in arryOfWordsToBeSearched) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"name contains[cd] %#",term];
[subpredicates addObject:p];
}
NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
//***************************************************************predicate made above******
result = [[NSMutableArray alloc]initWithArray:[arryOfDummyData filteredArrayUsingPredicate: filter]];//search on data array using predicate
Create table view controller subclass with nibfile. Add search bar to nibfile at top of table view. Then search result view controller will be added automatically.
most of the property of searchResultViewController like delegate, searchBar ,searchDisplayDatasource and delegate are automatically set. and also for search bar delegate is set as file owner.
Now implement table view conform to this protocol . .
Implement the following delegate method .
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
// create the array of ur search result object
}
now implementing tableViewDataSource and delegate check which table is calling method
as follows
if (tableView == self.searchDisplayController.searchResultsTableView)
{
// searchResultsTableView
}
else
{
// main table view
}
implement the corresponding code.

Memory Leak & App Crash when going back to Album List

I'm using three20 to create image viewer. First i'm creating list of albums from the sql db and when user selects any album, its url string is passed to the this code that creates thums of available pics on network using XML Parser. everything works fine but when user goes back to the album list and selects another album. app crashes with 'Thread 1: Program received singal: "EXC+BAD_ACCESS" in main.m. plus XCode Product Analyze gives potential memory leak where i'm creating photoSource in the viewDidLoad. Here is the code
#import "AlbumController.h"
#import "PhotoSource.h"
#import "Photo.h"
#import "AlbumInfo.h"
#import "AlbumDatabase.h"
#implementation AlbumController
#synthesize albumName;
#synthesize urlAddress;
#synthesize images;
- (void)viewDidLoad
{
[super viewDidLoad];
// NSLog(#"%#", self.urlAddress);
[self createPhotos]; // method to set up the photos array
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil];
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// release and set to nil
}
-(void)createPhotos
{
if ([stories count] == 0)
{
NSString *path = self.urlAddress;
[self parseXMLFileAtURL:path];
}
images = [NSMutableArray arrayWithCapacity:[stories count]]; // needs to be mutable
for (int i = 0; i < [stories count]; i++)
{
NSString *img = [[stories objectAtIndex:i] objectForKey:#"image"];
img = [img stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
//NSString * caption = [[stories objectAtIndex:i] objectForKey:#"caption"];
//caption = [caption stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
[images addObject:[[[Photo alloc] initWithURL:img smallURL:img size:CGSizeMake(320, 212)] autorelease]];
}
}
#pragma mark -
#pragma mark XML Parser Implementation
- (void)parserDidStartDocument:(NSXMLParser *)parser{
//NSLog(#"found file and started parsing");
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
stories = [[NSMutableArray alloc] init];
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[rssParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unfortunately it is not possible to load Pictures. Please check Internet Connection. (Error code %i )", [parseError code]];
//NSLog(#"error parsing XML: %#", errorString);
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Failed to load the feed." message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
//NSLog(#"found this element: %#", elementName);
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
// clear out our story item caches...
item = [[NSMutableDictionary alloc] init];
currentCaption = [[NSMutableString alloc] init];
//currentThumbnail = [[NSMutableString alloc] init];
currentImage = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"item"]) {
// save values to an item, then store that item into the array...
//[item setObject:currentThumbnail forKey:#"thumbnail"];
//[item setObject:currentCaption forKey:#"caption"];
[item setObject:currentImage forKey:#"image"];
[stories addObject:[[item copy] autorelease]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
// save the characters for the current item...
if ([currentElement isEqualToString:#"thumbnail"]) {
//[currentThumbnail appendString:string];
}// else if ([currentElement isEqualToString:#"caption"]) {
//[currentCaption appendString:string];
//}
else if ([currentElement isEqualToString:#"image"]) {
[currentImage appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"all done!");
NSLog(#"stories array has %d items", [stories count]);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
return YES;
}
else
{
return NO;
}
}
#pragma mark -
#pragma mark Memory Management
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[currentElement release];
[rssParser release];
[stories release];
[item release];
[currentCaption release];
//[currentThumbnail release];
[currentImage release];
[images release];
[stories release];
[super dealloc];
}
#end
and here is the didSelectRowAtIndexPath thats pushing this view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AlbumInfo *info = [_albumInfos objectAtIndex:indexPath.row];
AlbumController *albumController = [[AlbumController alloc] init];
albumController.urlAddress = info.address;
albumController.albumName = info.name;
[self.navigationController pushViewController:albumController animated:YES];
[albumController release];
}
Here is the code for AlbumController.h
#import <Foundation/Foundation.h>
#import "Three20/Three20.h"
#interface AlbumController : TTThumbsViewController <NSXMLParserDelegate>
{
NSString *albumName;
NSString *urlAddress;
// images
NSMutableArray *images;
// parser
NSXMLParser * rssParser;
NSMutableArray * stories;
NSMutableDictionary * item;
NSString * currentElement;
NSMutableString * currentImage;
NSMutableString * currentCaption;
}
#property (nonatomic, strong) NSString *albumName;
#property (nonatomic, strong) NSString *urlAddress;
#property (nonatomic, retain) NSMutableArray *images;
- (void)createPhotos;
- (void)parseXMLFileAtURL:(NSString *)URL;
#end
used this tutorial http://www.raywenderlich.com/1430/how-to-use-the-three20-photo-viewer
Need help solving this memory leak and need to know why its crashing.
Thanks
Simple. In Xcode 4.0+, Just click-hold on the Run icon, and press Profile. It'll open up Instruments, and you'll want Zombies. Then navigate your app to where the crash happened before, and this time, it'll show up in Instruments with the caller, and all the information about it.
The memory leak in viewDidLoad is caused by the following line:
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil];
[PhotoSource alloc] returns an object you own (with a retain count of +1).
initWithType:title:photos:photos2: does not change the retain count.
So viewDidLoad is left with an object it owns, but no pointer to it. To balance the alloc you should send an autorelease message:
self.photoSource = [[[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil] autorelease];

UITableView cell text is not showing xml data in iPhone application development

I am newer in iPhone application development. I want to find out why tableview cell is not showing data. I tried a lot of ways. I am giving my code below.
Note that I am seeing data at my console which is coming from XML file but it's not displaying in UITableView cell.
#synthesize newsTable;
#synthesize activityIndicator;
#synthesize rssParser;
#synthesize stories;
#synthesize item;
#synthesize currentElement;
#synthesize currentTitle, currentDate, currentSummary, currentLink;
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
*/
#pragma mark -
#pragma mark Parsing
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([stories count] == 0) {
NSString * path = #"http://icms7.bitmascot.com:8080/webcommander2.0S2/rest/services/catalogue/getAllDummyCategoryProduct";
[self parseXMLFileAtURL:path];
}
cellSize = CGSizeMake([newsTable bounds].size.width, 60);
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
stories = [[NSMutableArray alloc] init];
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[rssParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(#"found file and started parsing");
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSString * errorString = [NSString stringWithFormat:#"Unable to download story feed from web site (Error code %i )", [parseError code]];
NSLog(#"error parsing XML: %#", errorString);
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NSLog(#"found this element: %#", elementName);
currentElement = [elementName copy];
if ([elementName isEqualToString:#"ProductData"])
{
// clear out our story item caches...
item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentDate = [[NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentLink = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"ProductData"])
{ // save values to an item, then store that item into the array...
[item setObject:currentTitle forKey:#"id"];
[item setObject:currentLink forKey:#"productNumber"];
[item setObject:currentSummary forKey:#"name"];
[item setObject:currentDate forKey:#"dateCreated"];
[stories addObject:[item copy]];
NSLog(#"adding story: %#", currentTitle);
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([currentElement isEqualToString:#"ProductData"])
{
[currentTitle appendString:string];
}
else if ([currentElement isEqualToString:#"id"])
{
[currentLink appendString:string];
}
else if ([currentElement isEqualToString:#"ProductNumber"])
{
[currentSummary appendString:string];
}
else if ([currentElement isEqualToString:#"dateCreatrd"])
{
[currentDate appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
NSLog(#"all done!");
NSLog(#"stories array has %d items", [stories count]);
NSLog(#"data in stories: %#",[stories description]);
[newsTable reloadData];
}
#pragma mark tableView
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return [stories count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: MyIdentifier];
}
// Set up the cell
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
//[cell setText:[[stories objectAtIndex: storyIndex] objectForKey: #"title"]];
//[cell setLabelText:[[stories objectAtIndex:storyIndex] objectForKey: #"ProductData"]];
//[cell setText:[stories objectAtIndex:storyIndex]];
cell.textLabel.text = [stories objectAtIndex:storyIndex];
NSLog(#"%# ",cell.textLabel.text);
//cell.detailTextLabel.text = [stories objectAtIndex:indexPath.row];
return cell;
}
/*
- (void)setLabelText:(NSString *)_text{
UILabel *cellText;
cellText.text= _text;
[cellText sizeToFit];
}
*/
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[currentElement release];
[rssParser release];
[stories release];
[item release];
[currentTitle release];
[currentDate release];
[currentSummary release];
[currentLink release];
[super dealloc];
}
#end
Try to set value of property textLabel, not detailedTextLabel :
cell.textLabel.text = [[stories objectAtIndex:storyIndex] valueForKey:#"productNumber"];
Also try to create cell using predefined styles:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: MyIdentifier];
To make a cell you should use
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
method. By default the detailTextLabel is not visible in the cell.
Try to use other styles - UITableViewCellStyleValue1, for example.
Instead of giving,
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
//[cell setText:[[stories objectAtIndex: storyIndex] objectForKey: #"title"]];
//[cell setLabelText:[[stories objectAtIndex:storyIndex] objectForKey: #"ProductData"]];
//[cell setText:[stories objectAtIndex:storyIndex]];
cell.detailTextLabel.text = [stories objectAtIndex:storyIndex];
try this code:
cell.detailTextLabel.text = [stories objectAtIndex:indexPath.row];
before that ,just check your array(stories)having content?
Thank You..
cell.detailTextLabel.text = [stories objectAtIndex:storyIndex];
replace above statement with belo wstatement iy will work i think
cell.detailTextLabel.text = [stories objectAtIndex:indexPath.row];

iPhone: I'm stuck on my Sections in UITableView, data comes from XMLParser

I'm new to this forum and to iPhone development.
Due to the fact I know nobody who does iPhone development as well I am stuck and have to ask you guys for a solution.
I am making an application getting the data from an XMLParser, provides the Data to an UITableView in sections (months) within those sections are rows (stages).
When I run my script now it doesn't do this. I know I am close to the solution but I can't see it. And not having somebody to run my script with makes it difficult to debug.
My (Demo)XML File:
<?xml version="1.0" encoding="UTF-8"?>
<Stages>
<Month id="1" name="January">
<Stage id="1">
<title>Circumference</title>
<author>Nicholas Nicastro</author>
<summary>Eratosthenes and the Ancient Quest to Measure the Globe.</summary>
</Stage>
<Stage id="2">
<title>Copernicus Secret</title>
<author>Jack Repcheck</author>
<summary>How the scientific revolution began</summary>
</Stage>
<Stage id="3">
<title>Angels and Demons</title>
<author>Dan Brown</author>
<summary>Robert Langdon is summoned to a Swiss research facility to analyze a cryptic symbol seared into the chest of a murdered physicist.</summary>
</Stage>
</Month>
<Month id="2" name="February">
<Stage id="4">
<title>Keep the Aspidistra Flying</title>
<author>George Orwell</author>
<summary>A poignant and ultimately hopeful look at class and society, Keep the Aspidistra Flying pays tribute to the stubborn virtues of ordinary people who keep the aspidistra flying.</summary>
</Stage>
</Month>
</Stages>
My XMLParser class:
#import <UIKit/UIKit.h>
#class DAFAppDelegate, Stage, Month;
#interface XMLParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentElementValue;
DAFAppDelegate *appDelegate;
Stage *aStage;
Month *aMonth;
}
- (XMLParser *) initXMLParser;
#end
#import "XMLParser.h"
#import "DAFAppDelegate.h"
#import "Stage.h"
#import "Month.h"
#implementation XMLParser
- (XMLParser *) initXMLParser
{
[super init];
appDelegate = (DAFAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"Stages"])
{
//Initialize the array.
appDelegate.stages = [[NSMutableArray alloc] init];
}
if([elementName isEqualToString:#"Month"])
{
//Initialize the Month.
aMonth = [[Month alloc] init];
//Extract the attribute here.
aMonth.name = [attributeDict valueForKey:#"name"];
aMonth.monthID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading Month id value :%i", aMonth.monthID);
NSLog(#"Reading Month name value :%#", aMonth.name);
}
if([elementName isEqualToString:#"Stage"])
{
//Initialize the Stage.
aStage = [[Stage alloc] init];
//Extract the attribute here.
aStage.stageID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading id value :%i", aStage.stageID);
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(!currentElementValue)
{
currentElementValue = [[NSMutableString alloc] initWithString:string];
}
else
{
[currentElementValue appendString:string];
}
NSLog(#"Processing Value: %#", currentElementValue);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"Stages"])
return;
//There is nothing to do if we encounter the Stages element here.
//If we encounter the Stage element howevere, we want to add the book object to the array
// and release the object.
if([elementName isEqualToString:#"Month"])
{
[appDelegate.stages addObject:aMonth];
[aMonth release];
aMonth = nil;
}
if([elementName isEqualToString:#"Stage"])
{
[aMonth.monthStage addObject:aStage];
[aStage release];
aStage = nil;
}
else
{
[aStage setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
}
- (void) dealloc
{
[aStage release];
[aMonth release];
[currentElementValue release];
[super dealloc];
}
#end
My RootViewController:
#class DAFAppDelegate; //Here is my stages mutable array defined
#interface RootViewController : UITableViewController
{
DAFAppDelegate *appDelegate;
}
#end
#import "RootViewController.h"
#import "DAFAppDelegate.h"
#import "DetailViewController.h"
#import "Stage.h"
#import "Month.h"
#import "AgendaCustomCell.h"
#implementation RootViewController
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = (DAFAppDelegate *)[[UIApplication sharedApplication] delegate];
self.title = NSLocalizedString(#"Agenda", #"Master view navigation title");
UIImageView *image=[[UIImageView alloc]initWithFrame:CGRectMake(0,0,45,45)] ;
[image setImage:[UIImage imageNamed:#"topBarIcon.png"]];
[self.navigationController.navigationBar.topItem setTitleView:image];
self.tableView.backgroundColor = [UIColor clearColor];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [appDelegate.stages count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #"Month Name";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [appDelegate.stages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"AgendaCustomCell";
AgendaCustomCell *cell = (AgendaCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *topLevelObject = [[NSBundle mainBundle] loadNibNamed:#"AgendaCustomCell" owner:nil options:nil];
for (id currentObject in topLevelObject)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (AgendaCustomCell *)currentObject;
break;
}
}
}
UIView *cellBackView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:#"customCellBg.png"]];
cell.backgroundView = cellBackView;
Month *aMonth = [appDelegate.stages objectAtIndex:indexPath.section];
Stage *aStage = [aMonth.monthStage objectAtIndex:indexPath.row];
cell.titleLabel.text = aStage.title;
cell.dateLabel.text = aStage.author;
cell.nameLabel.text = aStage.summary;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;
}
#pragma mark -
#pragma mark Table view selection
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//When a row is selected, create the detail view controller and set its detail item to the item associated with the selected row.
DetailViewController *detailViewController = [[DetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
detailViewController.stage = [appDelegate.stages objectAtIndex:indexPath.row];
// Push the detail view controller.
[[self navigationController] pushViewController:detailViewController animated:YES];
[detailViewController release];
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc
{
[appDelegate release];
[super dealloc];
}
#end
Please help me out on this one. I have been breaking my head over this one for days now and it is driving me crazy.
Thanks in advanced!!!
NSXMLParser works in the background, so I'd say it's possible that when your RootViewController tableView is asking your appDelegate for [appDelegate.stages count]; it may not be ready or finished parsing the XML at that point.
Look at implementing 'parserDidEndDocument:' delegate call back and load the UITableView data after that call back.
The problem might be with your tableView:numberOfRowsInSection: implementation. You have it returning the number of sections, rather than the number of entries in the specified section. Based on your test XML, this will always return 1, which could be the problem you're seeing.
To get the number of entries in a section, based on your sample code I'd do something like this:
Month *aMonth = [appDelegate.stages objectAtIndex:section];
return [aMonth.monthStage count];
This will return the number of entries for a given month.
Load the xml without the singleton object means in your case appDelegate treat as a singleton.... make the property in the appDelegate of NSXMLParser, and when you intiate the object set to autorelease not in dealloc.

XML Parsing in Cocoa Touch/iPhone

Okay i have seen TouchXML, parseXML, NSXMLDocument, NSXMLParser but i am really confused with what to to do.
I have an iphone app which connects to a servers, requests data and gets XML response. Sample xml response to different set of queries is give at http://pastebin.com/f681c4b04
I have another classes which acts as Controller (As in MVC, to do the logic of fetch the data). This class gets the input from the View classes and processes it e.g. send a request to the webserver, gets xml, parses xml, populates its variables (its a singleton/shared Classes), and then responses as true or false to the caller. Caller, based on response given by the controller class, checks controller's variables and shows appropriate contents to the user.
I have the following Controller Class variables:
#interface backendController : NSObject {
NSMutableDictionary *searchResults, *plantInfoResults, *bookmarkList, *userLoginResult;
}
and functions like getBookmarkList, getPlantInfo. Right now i am printing plain XML return by the webserver by
NSLog(#"Result: :%#" [NSString stringWithContentsOfURL:url])
I want a generic function which gets the XML returned from the server, parseses it, makes a NSMutableDictionary of it containing XML opening tags' text representation as Keys and XML Tag Values as Values and return that.
Only one question, how to do that?.
Have you tried any of the XML Parsers you mentioned? This is how they set the key value of a node name:
[aBook setValue:currentElementValue forKey:elementName];
P.S. Double check your XML though, seems you are missing a root node on some of your results. Unless you left it out for simplicity.
Take a look at w3schools XML tutorial, it should point you in the right direction for XML syntax.
Consider the following code snippet, that uses libxml2, Matt Gallagher's libxml2 wrappers and Ben Copsey's ASIHTTPRequest to parse an HTTP document.
To parse XML, use PerformXMLXPathQuery instead of the PerformHTTPXPathQuery I use in my example.
The nodes instance of type NSArray * will contain NSDictionary * objects that you can parse recursively to get the data you want.
Or, if you know the scheme of your XML document, you can write an XPath query to get you to a nodeContent or nodeAttribute value directly.
ASIHTTPRequest *request = [ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:#"http://stackoverflow.com/"];
[request start];
NSError *error = [request error];
if (!error) {
NSData *response = [request responseData];
NSLog(#"Root node: %#", [[self query:#"//" withResponse:response] description]);
}
else
#throw [NSException exceptionWithName:#"kHTTPRequestFailed" reason:#"Request failed!" userInfo:nil];
[request release];
...
- (id) query:(NSString *)xpathQuery withResponse:(NSData *)respData {
NSArray *nodes = PerformHTMLXPathQuery(respData, xpathQuery);
if (nodes != nil)
return nodes;
return nil;
}
providing you one simple example of parsing XML in Table, Hope it would help you.
//XMLViewController.h
#import <UIKit/UIKit.h>
#interface TestXMLViewController : UIViewController<NSXMLParserDelegate,UITableViewDelegate,UITableViewDataSource>{
#private
NSXMLParser *xmlParser;
NSInteger depth;
NSMutableString *currentName;
NSString *currentElement;
NSMutableArray *data;
}
#property (nonatomic, strong) IBOutlet UITableView *tableView;
-(void)start;
#end
//TestXMLViewController.m
#import "TestXmlDetail.h"
#import "TestXMLViewController.h"
#interface TestXMLViewController ()
- (void)showCurrentDepth;
#end
#implementation TestXMLViewController
#synthesize tableView;
- (void)start
{
NSString *xml = #"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><Node><name>Main</name><Node><name>first row</name></Node><Node><name>second row</name></Node><Node><name>third row</name></Node></Node>";
xmlParser = [[NSXMLParser alloc] initWithData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
[xmlParser setDelegate:self];
[xmlParser setShouldProcessNamespaces:NO];
[xmlParser setShouldReportNamespacePrefixes:NO];
[xmlParser setShouldResolveExternalEntities:NO];
[xmlParser parse];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(#"Document started");
depth = 0;
currentElement = nil;
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(#"Error: %#", [parseError localizedDescription]);
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
currentElement = [elementName copy];
if ([currentElement isEqualToString:#"Node"])
{
++depth;
[self showCurrentDepth];
}
else if ([currentElement isEqualToString:#"name"])
{
currentName = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"Node"])
{
--depth;
[self showCurrentDepth];
}
else if ([elementName isEqualToString:#"name"])
{
if (depth == 1)
{
NSLog(#"Outer name tag: %#", currentName);
}
else
{
NSLog(#"Inner name tag: %#", currentName);
[data addObject:currentName];
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ([currentElement isEqualToString:#"name"])
{
[currentName appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"Document finished", nil);
}
- (void)showCurrentDepth
{
NSLog(#"Current depth: %d", depth);
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
data = [[NSMutableArray alloc]init ];
[self start];
self.title=#"XML parsing";
NSLog(#"string is %#",data);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
`enter code here`return [data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [data objectAtIndex:indexPath.row];
return cell;
}
#end