This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
Please do not close this topic.I really need help.
I am developing on IOS 6.Xcode-4.5.2
On a button click i get the below xml data from the server
<country>america</country>
<dateOfBirth xsi:nil="true"/>
<firstName>John</firstName>
<lastName>Smith</lastName>
<userEmail>johnsmith#email.com</userEmail>
I am trying to parse it and get the values.I did as per the example shown in this url http://www.edumobile.org/iphone/iphone-programming-tutorials/parsing-an-xml-file/
But i am getting an error when the parse method is called.
Instead of the appdelegate class as shown in the example url i am using the viewcontroller class.I do not want to add any code in the Appdelegate class.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AppDelegate setUserDetails:]: unrecognized selector sent to instance 0x9272a40'
I am just a beginner in iphone programming.So i need help in parsing this successfully and i just want to get the values somehow so that i can use them to show on screen in some labels.
Below are codes for 6 files(Viewcontroller.h & m,User.h & m,Xmlparser.h & m)
//ViewController.h
#import <UIKit/UIKit.h>
#import "GlobalVariable.h"
#import "QuotesViewController.h"
#interface ViewController : UIViewController <NSXMLParserDelegate,UIApplicationDelegate,NSStreamDelegate,UIAlertViewDelegate,WriteProtocol>
{
QuotesViewController *quoteobj;
NSMutableArray *userDetails;
}
#property (retain, nonatomic) IBOutlet UITextField *txtUsername;
#property (retain, nonatomic) IBOutlet UITextField *txtPassword;
#property (retain, nonatomic) NSInputStream *inputStream;
#property (retain, nonatomic) NSOutputStream *outputStream;
#property (nonatomic, retain) NSMutableArray *messages;
#property (retain, nonatomic) IBOutlet UILabel *label1;
- (IBAction)btnLogin:(id)sender;
- (IBAction)btnExit:(id)sender;
- (void)initNetworkCommunication;
- (void)readIn:(NSString *)s;
- (void)writeOut:(NSString *)s;
#property (nonatomic, retain) NSMutableArray *userDetails;
#end
//ViewController.m
#import "ViewController.h"
#import "NewTabViewController.h"
#import "QuotesViewController.h"
#import "XMLParser.h"
#implementation ViewController
#synthesize txtPassword,txtUsername,inputStream, outputStream,messages,label1,userDetails;
- (void)viewDidLoad
{
[super viewDidLoad];
quoteobj =[[QuotesViewController alloc]init];
quoteobj.myTableView = [[UITableView alloc]init];
quoteobj.myTableView.delegate=quoteobj;
quoteobj.myTableView.dataSource=quoteobj;
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)btnLogin:(id)sender {
NSLog(#"Clicked button1");
[self initNetworkCommunication];
NSString *response = [NSString stringWithFormat:#"POST\r\n\r\nTMS|Login|%#|%#",txtUsername.text,txtPassword.text];
NSLog(#"1");
[self writeOut:response];
}
- (IBAction)btnExit:(id)sender {
exit(0);
}
- (void) initNetworkCommunication {
NSLog(#"initNetworkCommunication called");
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"xxx.xxx.x.xx", xxxx, &readStream, &writeStream);
inputStream = (NSInputStream *)readStream;
outputStream = (NSOutputStream *)writeStream;
[inputStream retain];
[outputStream retain];
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %i", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
[self readIn:output];
if([output hasPrefix:#"JSESSIONID"]){
int len = [output length];
int lenn = len-29;
sessionId = [output substringWithRange:NSMakeRange(0, lenn)];
label1.text=sessionId;
NSLog(#"New String %# LENGTH SESSUIn %i",sessionId,sessionId.length);
sessionId=label1.text;
NewTabViewController *so = [self.storyboard instantiateViewControllerWithIdentifier:#"newtab"];
for(UIViewController *ssa in so.viewControllers){
if([ssa isKindOfClass:[QuotesViewController class]]){
QuotesViewController *qq = (QuotesViewController *) ssa;
NSLog(#"PREESENTING THIS FZZZZZZZZZZZzzaaadfsdfssdfsa");
[qq setDel:self];
}
}
[self presentViewController:so animated:YES completion:nil];
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
UIAlertView *alert =[[UIAlertView alloc]initWithTitle:#"Server says.." message:#"Due to some reason server is unavailable" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alert show];
[alert release];
break;
case NSStreamEventEndEncountered:
NSLog(#"NSStreamEventEndEncountered:method is called");
[theStream close];
NSLog(#"theStream is closed");
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
NSLog(#"theStream is removed from runloop");
[theStream release];
NSLog(#"theStream is released");
NSLog(#"Server is unavailable");
theStream = nil;
if(theStream==nil){
UIAlertView *alert =[[UIAlertView alloc]initWithTitle:#"Server says.." message:#"Due to some reason server is unavailable" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alert show];
[alert release];
}
NSLog(#"IT reaches 1 here");
break;
default:
NSLog(#"Unknown event");
}
}//End of stream
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSLog(#"IT reaches here");
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Ok"])
{
NSLog(#"Ok is clicked");
exit(0);
}
}
- (void) messageReceived:(NSString *)message {
NSLog(#"Entered MessageRecieved");
[messages addObject:message];
}
- (void)readIn:(NSString *)s {
NSLog(#"%#", s);
if ([s hasPrefix:#"{"]) {
if([s rangeOfString:#"instrSymbol"].location ==NSNotFound){
NSLog(#"Received a data which is not instrumentid");
}
else{
NSLog(#"JSON DATA RECEIVED");
[quoteobj parseJsonData:s];
}
}
else if([s hasPrefix:#"<"]){
NSLog(#"XML DATA RECEIVED");
NSData *xmlData= [[NSData alloc]initWithData:[s dataUsingEncoding:NSUTF8StringEncoding]];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:xmlData];
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
}
}
- (void)writeOut:(NSString *)s {
if (outputStream) {
NSLog(#"WRITING OUT");
uint8_t *buf = (uint8_t *)[s UTF8String];
[outputStream write:buf maxLength:strlen((char *)buf)];
NSLog(#"Writing out the following:");
NSLog(#"%#", s);
}
else{
NSLog(#"Noutoyt");
}
}
#end
//XMLParser.h
#import <Foundation/Foundation.h>
#class ViewController,User;
#interface XMLParser : NSObject{
NSMutableString *currentElementValue;
ViewController *zappDelegate;
User *aBook;
}
- (XMLParser *) initXMLParser;
#end
//XMLParser.m
#import "XMLParser.h"
#import "ViewController.h"
#import "User.h"
#implementation XMLParser
- (XMLParser *) initXMLParser {
[super init];
zappDelegate = (ViewController *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"country"]) {
//Initialize the array.
zappDelegate.userDetails = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"firstName"]) {
//Initialize the book.
aBook = [[User alloc] init];
//Extract the attribute here.
//aBook.bookID = [[attributeDict objectForKey:#"id"] integerValue];
//NSLog(#"Reading id value :%i", aBook.bookID);
}
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:#"Books"])
return;
if([elementName isEqualToString:#"Book"]) {
[zappDelegate.userDetails addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
#end
//User.h
#import <Foundation/Foundation.h>
#interface User : NSObject {
//NSInteger bookID;
NSString *firstName; //Same name as the Entity Name.
NSString *lastName; //Same name as the Entity Name.
NSString *userEmail; //Same name as the Entity Name.
}
#property (nonatomic, retain) NSString *firstName;
#property (nonatomic, retain) NSString *lastName;
#property (nonatomic, retain) NSString *userEmail;
#end
//User.m
#import "User.h"
#implementation User
#synthesize firstName,lastName,userEmail;
- (void) dealloc {
[firstName release];
[lastName release];
[userEmail release];
[super dealloc];
}
#end
You created a class called ViewController but then you try assigning an instance of it in the XMLParser class by casting the application delegate which is unrelated.
zappDelegate = (ViewController *)[[UIApplication sharedApplication] delegate];
You need to change the name of zappDelegate to something more appropriate and assign it a real instance of your ViewController.
I do notice that your ViewController does conform to the UIApplicationDelegate protocol but that does not automatically make it the applications delegate. The real delegate should be properly setup in the main.m[m] file.
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
Check this link i modified the source :
http://dcraziee.wordpress.com/2013/05/29/parsing-xml-in-objective-c/
It will return you the dictionary from your xml response.
All the keys in your xml will be a key and value will in value part of dictionary.
If you contains hierarchal xml then will be managed accordingly.
I hope this will help.
Related
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];
I load data into my UITableView from an NSXMLParser.
This all works fine but what I would like to implement is some short of activity when the App is loading the XML data, so it all is a bit more friendly for the users.
Some samples I have found still confuse me simply because I did not follow the same way of XMLParser implementation as most same do.
I provide my data here, please give some code samples on how I should put it in my code.
XMLParser.h:
#import <UIKit/UIKit.h>
#class DAFAppDelegate, Stage, Month;
#interface XMLParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentElementValue;
DAFAppDelegate *appDelegate;
Stage *aStage;
Month *aMonth;
}
- (XMLParser *) initXMLParser;
+ (NSDate *)dateFromString:(NSString *)dateString;
+ (NSString *)stringFromDate:(NSDate *)stringDate;
#end
XMLParser.m:
#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];
aMonth.stagesPerMonth = [[NSMutableArray 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
{
NSDate* date = [NSDate date];
NSDateFormatter* nsformatter = [[[NSDateFormatter alloc] init] autorelease];
[nsformatter setDateFormat:#"yyyy-MM-dd"];
NSDate* stageDate = [XMLParser dateFromString:aStage.end];
if([elementName isEqualToString:#"Stages"])
{
return;
}
if([elementName isEqualToString:#"Month"])
{
if (!aMonth.stagesPerMonth || aMonth.stagesPerMonth.count)
{
[appDelegate.stages addObject:aMonth];
}
[aMonth release];
aMonth = nil;
}
if([elementName isEqualToString:#"Stage"])
{
NSTimeInterval interval = [date timeIntervalSinceDate:stageDate];
if (interval < 0)
{
[aMonth.stagesPerMonth addObject:aStage];
}
[aStage release];
aStage = nil;
}
else
{
[aStage setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
}
-(void) parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(#"parserDidStartDocument");
}
-(void) parserDidEndDocument: (NSXMLParser *)parser
{
NSLog(#"parserDidEndDocument");
}
+ (NSDate *)dateFromString:(NSString *)dateString
{
NSDateFormatter *nsDateFormatter = [[NSDateFormatter alloc] init];
[nsDateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm"];
NSDate *date = [nsDateFormatter dateFromString:dateString];
return date;
[nsDateFormatter release];
}
+ (NSString *)stringFromDate:(NSDate *)stringDate
{
NSDateFormatter *stringDateFormatter = [[NSDateFormatter alloc] init];
NSLocale *nlLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"nl_NL"];
[stringDateFormatter setLocale:nlLocale];
[stringDateFormatter setDateFormat:#"EEE', 'dd MMMM yyyy HH:mma"];
NSString *dateString = [stringDateFormatter stringFromDate:stringDate];
return dateString;
[stringDateFormatter release];
}
- (void) dealloc
{
[aStage release];
[aMonth release];
[currentElementValue release];
[super dealloc];
}
#end
DAFAppDelegate.h:
#class RootViewController;
#interface DAFAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
UINavigationController *navigationController;
IBOutlet UITabBarController *rootTabController;
RootViewController *rootViewController;
NSMutableArray *stages;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *rootTabController;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#property (nonatomic, retain) IBOutlet RootViewController *rootViewController;
#property (nonatomic, retain) NSMutableArray *stages;
+ (void) showAlert;
#end
DAFAppDelegate.m:
#import "DAFAppDelegate.h"
#import "RootViewController.h"
#import "XMLParser.h"
#implementation DAFAppDelegate
#synthesize window;
#synthesize navigationController;
#synthesize rootViewController;
#synthesize rootTabController;
#synthesize stages;
+ (void) showAlert
{
UIAlertView *av = [[[UIAlertView alloc] initWithTitle:#"No Connection" message:#"Could not retrieve data" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[av show];
}
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
NSURL *url = [[NSURL alloc] initWithString:#"http://web.me.com/ijar/Stages.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
{
NSLog(#"No Errors");
}
else
{
[DAFAppDelegate showAlert];
NSLog(#"Error Error Error!!!");
}
[window addSubview:[rootTabController view]];
[window makeKeyAndVisible];
}
- (void)dealloc
{
[navigationController release];
[rootViewController release];
[rootTabController release];
[window release];
[stages release];
[super dealloc];
}
#end
RootViewController.h:
#class DAFAppDelegate;
#interface RootViewController : UITableViewController
{
DAFAppDelegate *appDelegate;
}
#end
RootViewController.m:
#import "RootViewController.h"
#import "DAFAppDelegate.h"
#import "DetailViewController.h"
#import "XMLParser.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
{
Month *aMonth = [appDelegate.stages objectAtIndex:section];
return aMonth.name;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
Month *aMonth = [appDelegate.stages objectAtIndex:section];
return [aMonth.stagesPerMonth 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;
}
}
}
Month *aMonth = [appDelegate.stages objectAtIndex:indexPath.section];
Stage *aStage = [aMonth.stagesPerMonth objectAtIndex:indexPath.row];
NSString *startDate = [XMLParser stringFromDate:[XMLParser dateFromString:aStage.start]];
NSString *endDate = [XMLParser stringFromDate:[XMLParser dateFromString:aStage.end]];
int endDateLength = endDate.length;
NSString *dateTitle = [NSString stringWithFormat:#"%# - %#", startDate, [endDate substringFromIndex:endDateLength -7]];
cell.titleLabel.text = aStage.title;
cell.dateLabel.text = dateTitle;
cell.nameLabel.text = aStage.teacher;
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];
Month *aMonth = [appDelegate.stages objectAtIndex:indexPath.section];
detailViewController.stage = [aMonth.stagesPerMonth 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
If you want to use the standard activity indicator in the status bar call:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
Just before you call the parser.
Then once the parser is complete (the didEndDocument method), call:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
I'm not going to write the code for you, but here are some steps you could take.
1. For a better UX, add the RootViewController.view to the window before you start the xml parsing.
2. In your RootViewController: viewDidLoad method, create and display a UIActivityIndicatorView (a "spinner").
3. When your parsing is done, call a method on the RootViewController that does 3 things:
a) hides the spinner
b) loads the tableView's data source (aMonth.stagesPerMonth)
c) tableView[reloadData];
Good luck.
-Mike
i want to read a HTML File with this command:
parseHTML = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:[#"http://theurl.com"]];
[parseHTML setDelegate:self];
[parseHTML parse];
in the didStartElement method i want to stop the actual parser after he found a specified string and parse a new site with these information:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if(somethingfound)
{
[parseHTML abortParsing];
parseHTML2 = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:[#"http://theurl.com" stringByAppendingString:product_link]]];
[parseHTML2 setDelegate:self];
[parseHTML2 parse];
}
}
i get an irregular error:
Thread1: Program received signal: "EXC
BAD ACCESS"
any ideas?
regards
Hello Walter thanks for your comment, here is the complete implementation:
I hope it helps... :-/
FirstViewController.h
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController <ZBarReaderDelegate, NSXMLParserDelegate>{
UIImageView *resultImage;
UITextView *resultText;
NSString *product_link;
NSXMLParser *parseHTML;
NSXMLParser *parseHTML2;
}
#property (nonatomic, retain) IBOutlet UIImageView *resultImage;
#property (nonatomic, retain) IBOutlet UITextView *resultText;
#property (nonatomic, assign) IBOutlet NSString *product_link;
#property (nonatomic, assign) NSXMLParser *parseHTML;
#property (nonatomic, assign) NSXMLParser *parseHTML2;
#property (nonatomic, retain) NSMutableArray *myMutableArray;
- (IBAction) scanButtonTapped;
#end
FirtViewController.m
#import "FirstViewController.h"
#import "/System/Library/Frameworks/Foundation.framework/Headers/NSDebug.h"
#implementation FirstViewController
#synthesize resultImage, resultText;
#synthesize product_link;
#synthesize parseHTML, parseHTML2;
bool link_is_here = false;
bool allergy_is_here = false;
bool parse_one_ok = true;
int hoch = 0;
- (IBAction) scanButtonTapped
{
NSZombieEnabled = true;
// ADD: present a barcode reader that scans from the camera feed
ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
ZBarImageScanner *scanner = reader.scanner;
// TODO: (optional) additional reader configuration here
// EXAMPLE: disable rarely used I2/5 to improve performance
[scanner setSymbology: ZBAR_I25
config: ZBAR_CFG_ENABLE
to: 0];
// present and release the controller
[self presentModalViewController: reader animated: YES];
[reader release];
}
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
// ADD: get the decode results
id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results)
break;
// EXAMPLE: do something useful with the barcode data
resultText.text = symbol.data;
parseHTML = [[[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:[#"http://URL.de/suche/?q=" stringByAppendingString:symbol.data]] ]autorelease];
[parseHTML setDelegate:self];
[parseHTML parse];
// [parseHTML release];
// EXAMPLE: do something useful with the barcode image
resultImage.image =
[info objectForKey: UIImagePickerControllerOriginalImage];
// ADD: dismiss the controller (NB dismiss from the *reader*!)
[reader dismissModalViewControllerAnimated: YES];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
for(NSString *key in [attributeDict allKeys]) {
if ([[attributeDict valueForKey:key] isEqualToString:#"some_string"]) {
link_is_here = true;
}
if ([key isEqualToString:#"href"] && link_is_here) {
product_link = [attributeDict valueForKey:key];
// [parseHTML abortParsing];
parseHTML2 = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:[#"http://URL.de" stringByAppendingString:product_link]]];
[parseHTML2 setDelegate:self];
[parseHTML2 parse];
parse_one_ok = true;
link_is_here = false;
}
if ([key isEqualToString:#"id"] && [[attributeDict valueForKey:key] isEqualToString:#"other_string"]) {
allergy_is_here = true;
}
if ([key isEqualToString:#"title"] && allergy_is_here) {
NSLog(#"DO: %#",[attributeDict valueForKey:key]);
}
if ([key isEqualToString:#"id"] && [[attributeDict valueForKey:key] isEqualToString:#"string"]) {
allergy_is_here = false;
parse_one_ok = true;
NSLog(#"Parser off");
//close all parser
}
}
}
-(void) parserDidEndDocument:(NSXMLParser *)parser{
[parseHTML setDelegate:nil];
[parseHTML2 setDelegate:nil];
[parseHTML release];
if (parse_one_ok) {
[parseHTML2 release];
}
}
- (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 {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[parseHTML release];
[parseHTML2 release];
self.product_link = nil;
self.resultImage = nil;
self.resultText = nil;
[super dealloc];
}
#end
hey my declaration is in the header:
#interface FirstViewController : UIViewController <NSXMLParserDelegate>{
NSString *product_link;
NSXMLParser *parseHTML;
NSXMLParser *parseHTML2;
}
#property (nonatomic, retain) IBOutlet NSString *product_link;
#property (nonatomic, retain) NSXMLParser *parseHTML;
#property (nonatomic, retain) NSXMLParser *parseHTML2;
and in the source:
#synthesize parseHTML, parseHTML2;
#synthesize product_link;
i get these exception in console:
-[NSCFString setDelegate:]: unrecognized selector sent to instance
0x1acad0
When I have to parse two files at once I set up a second delegate for the second file. The delegate is a simple NSObject that adheres to the NSXML Parser Delegate protocol. (It has the parserDidStart, parserDidEnd, blah blah blah).
Then in my didEndElement of my first parser I kick off the second parser with something like this
SoundCloudParser *scParser = [[[SoundCloudParser alloc] init]autorelease];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init]autorelease];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:scParser selector:#selector(parseXMLUrl:) object:currentArticle.uriString];
[queue addOperation:operation];
[operation release];
I do it on a separate thread which is why you have the queue in there. My 'parseXMLUrl:looks just like a regular one, it just sets the delegate to my second delegate object instead of setting it toself`.
One other thing you need to think about is that you are doing work at the didStartElement and I find that a lot of times I don't have any values in my parsing variables until I get to didEndElement. That would be something else for you to check.
UPDATE: In the future, if you are trying to build on something like ZBarSDK or another project, please say so. It would have saved me about half an hour of messing around with your code.
Basically what we need to do is to set up a new delegate. Let's call it newDelegate. Set it up as a regular NSObject and make it follow <NSXMLDelegate> protocol. It needs a mutableArray or a dictionary to store the data it will parse and it needs a function to kick it off. And that's about it.
So, let's assume you have created newDelegate.h and newDelegate.m in your project and in newDelegate.h you have
#import "Your_App_Delegate.h"
#interface newDelegate : NSObject {
NSMutableString *currentElement;
NSMutableArray *currentArticle;
}
- (void)parseXMLUrl:(NSString *)URL;
#end
So, now in your didStartElement you would call the newDelegate like this:
newDelegate *ndParser = [[[newDelegateParser alloc] init]autorelease];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init]autorelease];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:ndParser selector:#selector(parseXMLUrl:) object:[NSString stringWithFormat:#"http://URL.de/%#",product_link]];
[queue addOperation:operation];
[operation release];
This would kick off the second parser and pass it the url to parse. You will need a way to get that data, so either store some results in your App Delegate or else change the parseXMLURL method of the second parser to return some value.
hello i want to parse html an with this information another html file...
after 1-5 call the program crashes...
header:
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController <ZBarReaderDelegate, NSXMLParserDelegate>{
UIImageView *resultImage;
UITextView *resultText;
NSString *product_link;
NSXMLParser *parseHTML;
NSXMLParser *parseHTML2;
NSMutableArray *myMutableArray;
id <NSXMLParserDelegate> testkollege, asdf;
}
#property (nonatomic, retain) IBOutlet UIImageView *resultImage;
#property (nonatomic, retain) IBOutlet UITextView *resultText;
#property (nonatomic, assign) IBOutlet NSString *product_link;
#property (nonatomic, assign) NSXMLParser *parseHTML;
#property (nonatomic, assign) NSXMLParser *parseHTML2;
#property (nonatomic, retain) NSMutableArray *myMutableArray;
#property (nonatomic, assign) id <NSXMLParserDelegate> testkollege;
#property (nonatomic, assign) id <NSXMLParserDelegate> asdf;
- (IBAction) scanButtonTapped;
#end
m-file:
#import "FirstViewController.h"
#import "/System/Library/Frameworks/Foundation.framework/Headers/NSDebug.h"
#implementation FirstViewController
#synthesize resultImage, resultText;
#synthesize product_link;
#synthesize parseHTML, parseHTML2;
#synthesize myMutableArray;
#synthesize testkollege, asdf;
bool link_is_here = false;
bool allergy_is_here = false;
bool parse_one_ok = true;
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
// ADD: get the decode results
id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results)
// EXAMPLE: just grab the first barcode
break;
// EXAMPLE: do something useful with the barcode data
resultText.text = symbol.data;
// EXAMPLE: do something useful with the barcode image
resultImage.image =
[info objectForKey: UIImagePickerControllerOriginalImage];
// ADD: dismiss the controller (NB dismiss from the *reader*!)
[reader dismissModalViewControllerAnimated: YES];
parseHTML = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:[#"http://url.com/suche/?q=" stringByAppendingString:symbol.data]] ];
NSLog(#"parser 1 start");
[parseHTML setDelegate:self];
[parseHTML parse];
NSLog(#"parser 1 ready");
[parseHTML release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
for(NSString *key in [attributeDict allKeys]) {
if ([[attributeDict valueForKey:key] isEqualToString:#"search-result"]) {
link_is_here = true;
}
if ([key isEqualToString:#"href"] && link_is_here) {
product_link = [attributeDict valueForKey:key];
[parser abortParsing];
parseHTML2 = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:[#"http://url.com" stringByAppendingString:product_link]]];
[parseHTML2 setDelegate:self];
parse_one_ok = true;
link_is_here = false;
[parseHTML2 parse];
}
if ([key isEqualToString:#"id"] && [[attributeDict valueForKey:key] isEqualToString:#"nutrition-allergy"]) {
allergy_is_here = true;
}
if ([key isEqualToString:#"title"] && allergy_is_here) {
NSLog(#"keys: %#",[attributeDict valueForKey:key]);
}
if ([key isEqualToString:#"id"] && [[attributeDict valueForKey:key] isEqualToString:#"another string"]) {
allergy_is_here = false;
parse_one_ok = true;
NSLog(#"Parser off");
[parser abortParsing];
}
}
}
-(void) parserDidEndDocument:(NSXMLParser *)parser{
if (parse_one_ok) {
[parseHTML2 release];
parse_one_ok = false;
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
}
- (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 {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[parseHTML release];
[parseHTML2 release];
self.product_link = nil;
self.resultImage = nil;
self.resultText = nil;
[super dealloc];
}
#end
that is simple. You are releasing ParseHTML NSXMLPArsetwice.
-(void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
in the lastline
-(void)dealloc.
A object should be release only if you have earned the ownership. by retain copy etc. But you have allocated it only once so should release only once. But you did two releases .
You are also releasing NSXMLParser object parseHTML2 thrice. As per your code at any stage parseHTML2 will be released at least twice which is retained only once. ParseHTML1 objects case have been mentioned above
Regards,
Jackson Sunny Rodrigues
Turn on NSZombieEnabled. You are obviously releasing something you shouldn't be. When you do this, it will show you exactly where the bad access is occurring and you can trace back to where you are releasing the object. Check out this tutorial:
http://www.codza.com/how-to-debug-exc_bad_access-on-iphone
Best to learn how to fix it and what's wrong :)
I'm pulling data from an API and filling a UITableView with article titles (from Article objects). I have that part working, as far as I can tell. Where I'm having a hard time is trying to show the details of the article when a row is touched on the table view.
I'm correctly capturing the article ID, and then I make a request out to the API to pull it's data and do a very similar thing to what I'm doing to load the articles UITableView in the step before. Here's my parser for getting article details:
// ArticleDetailParser.h
#import <Foundation/Foundation.h>
#import "Article.h"
#class Article;
#class ArticleDetailParser;
#protocol ArticleDetailParserDelegate <NSObject>
- (void)parserDidFinish:(ArticleDetailParser *)parser;
- (void)parser:(ArticleDetailParser *)parser didFailWithError:(NSError *)error;
#end
#interface ArticleDetailParser : NSObject <NSXMLParserDelegate> {
id<ArticleDetailParserDelegate> delegate;
NSMutableString *currentCharacters;
Article *currentArticle;
NSMutableArray *articlesCollection;
NSMutableData *xmlData;
NSURLConnection *connectionInProgress;
}
#property (nonatomic, assign) id<ArticleDetailParserDelegate> delegate;
- (void)parseUrl:(NSString *)url;
- (void)beginParsing:(NSURL *)xmlUrl;
- (Article *)detailedArticle;
#end
And here's the implementation:
// ArticleDetailParser.m
#import "ArticleDetailParser.h"
#implementation ArticleDetailParser
#synthesize delegate;
#pragma mark -
#pragma mark Parsing methods
- (void)parseUrl:(NSString *)url
{
NSURL *xmlUrl = [NSURL URLWithString:url];
[self beginParsing:xmlUrl];
}
- (void)beginParsing:(NSURL *)xmlUrl
{
[articlesCollection removeAllObjects];
articlesCollection = [[NSMutableArray alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:xmlUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
// clear existing connection if there is one
if (connectionInProgress) {
[connectionInProgress cancel];
[connectionInProgress release];
}
[xmlData release];
xmlData = [[NSMutableData alloc] init];
// asynchronous connection
connectionInProgress = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
- (Article *)detailedArticle
{
return [articlesCollection objectAtIndex:0];
}
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[xmlData appendData:data];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqual:#"article"]) {
currentArticle = [[Article alloc] init];
return;
}
if ([elementName isEqual:#"id"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
if ([elementName isEqual:#"title"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
if ([elementName isEqual:#"alphabetical_title"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
if ([elementName isEqual:#"body"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
if ([elementName isEqual:#"body_html"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
if ([elementName isEqual:#"category"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
if ([elementName isEqual:#"authors"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
if ([elementName isEqual:#"last_updated"]) {
currentCharacters = [[NSMutableString alloc] init];
return;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[currentCharacters appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqual:#"article"]) {
[articlesCollection addObject:currentArticle];
[currentArticle release], currentArticle = nil;
return;
}
if ([elementName isEqual:#"id"]) {
[currentArticle setArticleID:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
if ([elementName isEqual:#"title"]) {
[currentArticle setTitle:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
if ([elementName isEqual:#"alphabetical_title"]) {
[currentArticle setAlphabeticalTitle:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
if ([elementName isEqual:#"body"]) {
[currentArticle setBody:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
if ([elementName isEqual:#"body_html"]) {
[currentArticle setBodyHtml:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
if ([elementName isEqual:#"category"]) {
[currentArticle setCategory:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
if ([elementName isEqual:#"authors"]) {
[currentArticle setAuthors:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
if ([elementName isEqual:#"last_updated"]) {
[currentArticle setLastModified:currentCharacters];
[currentCharacters release], currentCharacters = nil;
return;
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
[parser setDelegate:self];
[parser parse];
[parser release];
[delegate parserDidFinish:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[currentArticle release];
currentArticle = nil;
[currentCharacters release];
currentCharacters = nil;
[articlesCollection release];
articlesCollection = nil;
[connectionInProgress release];
connectionInProgress = nil;
[xmlData release];
xmlData = nil;
NSLog(#"connection failed: %#", [error localizedDescription]);
[delegate parser:self didFailWithError:error];
}
#end
Does anything stand out at you as being wrong? Here's my controller where I'm making use of the ArticleDetailParser:
// ArticleDetailViewController.h
#import <UIKit/UIKit.h>
#import "ArticleDetailParser.h"
#class Article;
#interface ArticleDetailViewController : UIViewController <ArticleDetailParserDelegate> {
Article *article;
UILabel *aTitle;
UILabel *aCategory;
UILabel *aAuthors;
UIActivityIndicatorView *activityView;
}
#property (nonatomic, assign) Article *article;
#property (nonatomic, assign) UIActivityIndicatorView *activityView;
- (void)loadArticleDetail;
- (void)showArticle;
#end
And the implementation of said controller:
// ArticleDetailViewController.m
#import "ArticleDetailViewController.h"
#implementation ArticleDetailViewController
#synthesize article, activityView;
#pragma mark -
#pragma mark init and dealloc
- (id)init
{
[super initWithNibName:nil bundle:nil];
[[self navigationItem] setTitle:#"Article Details"];
article = [[Article alloc] init];
aTitle = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 280, 25)];
aCategory = [[UILabel alloc] initWithFrame:CGRectMake(20, 30, 280, 25)];
aAuthors = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, 280, 25)];
activityView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[[self activityView] sizeToFit];
[[self activityView] setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)];
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
return [self init];
}
- (void)dealloc {
[article release];
[aTitle release];
[aCategory release];
[aAuthors release];
[activityView release];
[super dealloc];
}
#pragma mark -
#pragma mark Web Service methods
- (void)loadArticleDetail
{
NSString *urlToRequest = [NSString stringWithFormat:#"http://wvencyclopedia.org/articles/%#.xml", [[self article] articleID]];
ArticleDetailParser *aDetailParser = [[ArticleDetailParser alloc] init];
[aDetailParser setDelegate:self];
[aDetailParser parseUrl:urlToRequest];
[aDetailParser release];
}
#pragma mark -
#pragma mark ArticleDetailParserDelegate methods
- (void)parserDidFinish:(ArticleDetailParser *)parser
{
article = [parser detailedArticle];
[[self activityView] stopAnimating];
}
- (void)parser:(ArticleDetailParser *)parser didFailWithError:(NSError *)error
{
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:errorString delegate:nil cancelButtonTitle:#"OK" destructiveButtonTitle:nil otherButtonTitles:nil];
[actionSheet showInView:[[self view] window]];
[actionSheet autorelease];
}
#pragma mark -
#pragma mark UIView methods
- (void)showArticle
{
[aTitle setText:[[self article] title]];
[[self view] addSubview:aTitle];
[aTitle release];
[aCategory setText:[[self article] category]];
[[self view] addSubview:aCategory];
[aCategory release];
[aAuthors setText:[[self article] authors]];
[[self view] addSubview:aAuthors];
[aAuthors release];
}
#pragma mark -
#pragma mark UIViewController methods
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self loadArticleDetail];
[[self activityView] startAnimating];
[self showArticle];
}
- (void)viewDidLoad {
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor groupTableViewBackgroundColor]];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)loadView
{
[super loadView];
UIBarButtonItem *loadingView = [[UIBarButtonItem alloc] initWithCustomView:[self activityView]];
[[self navigationItem] setRightBarButtonItem:loadingView];
}
#pragma mark -
#pragma mark Memory Management
- (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.
}
#end
This is my first real iPhone application outside of tutorials in books, and I'm new to Objective-C as well, so I could easily be misunderstanding the memory management aspects, as well as getting labels on the view.
What's happening is I click on the table view to load an article, and for the first one it will display the article title only. Then I go back, try to click another and it crashes.
I'm sorry to post this much code, but I figured if someone chooses to help it might be best to have the whole picture.
Thanks SO much in advance, if you should take on such a task!
The reason your app is crashing could be due to your UILabels getting deallocated when you release them in showArticle:.
You'll want to use
#property (nonatomic, retain)
instead of
#property (nonatomic, assign)
when dealing with objects (variable types that require the star in front of the name). Use assign for primitive types like integers and doubles.