Accessing properties of objects in array to display in UITableViewCell - objective-c

I am using an XML parser to get information from a blog to create a feed reader app. I created an object with properties that are the data for each blog entry (title, published, author...). I'm storing the data in the object, then using a pointer to put the object in an array of parsed data. When I go to access the properties to display them in my UITableView, every cell is the same, with the last blog entry's data for every one.
parser .m file
#interface Parser()
//This property holds the blog objects that were parsed
#property (nonatomic, strong) NSMutableArray *parsedResults;
//This property holds the current element content being parsed
#property (nonatomic, strong) NSString *currentElement;
#property (nonatomic, strong) FRFeedItem *blogEntry;
#end
#implementation SolsticeParser
#synthesize parsedResults = _parsedResults;
#synthesize currentElement = _currentElement;
// Will be used to truncate data parsed from publish tag so that it will only store the YYYY-MM-DD to self.blogEntry.datepublished
NSRange dateOnly = {0, 10};
//This method initializes the parser, sets the delegate, starts parsing, and returns the results.
- (NSMutableArray *)parseFeedWithResults:(NSURL *)URL
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
parser.delegate = self;
self.parsedResults = [[NSMutableArray alloc] init];
[parser parse]; // Everything parsed here
return self.parsedResults;
}
...Here parsed data is saved to the properties of the BlogEntry object...
#pragma mark - Parser delegate
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
// Custom blog object initialized here
if ([elementName isEqualToString:#"entry"]) {
if (!self.blogEntry) {
self.blogEntry = [[FRFeedItem alloc] init];
}
}
}
...
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"title"]) {
self.blogEntry.title = self.currentElement;
} else if([elementName isEqualToString:#"published"]) {
self.blogEntry.datePublished = [self.currentElement substringWithRange:dateOnly];
} else if([elementName isEqualToString:#"entry"]) {
[self.parsedResults addObject:self.blogEntry];
}
}
In MyTableViewController.m:
#interface MyTableViewController ()
#property (nonatomic, strong) Parser* parser;
#property (nonatomic, strong) NSMutableArray* feedDataFromParser;
#end
#implementation MyTableViewController
// synthesize automatically done by Xcode v4.6
- (void)viewDidLoad
{
[super viewDidLoad];
self.parser = [[Parser alloc] init]; // initialize parser by allocating memory on the heap
[self loadItems]; // automatically loads data to be displayed upon opening the app
}
- (void)loadItems
{
// information parsed from blog stored to a mutable array
self.feedDataFromParser = [self.parser parseFeedWithResults:[NSURL URLWithString:kFeedURL]];
}
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//code not included for this question for brevity
// Configure the cell from data stored in mutable array of FRFeedItem objects
// PROBLEM:
cell.textLabel.text = [[self.feedDataFromParser objectAtIndex:indexPath.row] title];
cell.detailTextLabel.text = [[self.feedDataFromParser objectAtIndex:indexPath.row] datePublished];
return cell;
}
#end
As far as I can tell, there is nothing syntactically wrong. I've tried printing out the data parsed and saved to the object in the parser file as well as the value of indexPath.row, and both are correct.
What am I missing??

I think the problem is this line:
if (!self.blogEntry)
After you create the first one, you won't create any more. Try removing that if clause, and see if that fixes it.

Related

Feeding XML into custom objects?

I have some XML being returned from a web query, with multiple parameters wrapped up inside a tag, like so:
<game>
<name>First game title</name>
<id>12345</id>
<desc>A game..</desc>
</game>
<game>
<name>Second game title</name>
<id>67890</id>
<desc>Another game..</desc>
</game>
I'm using NSXMLParser to parse it, and it's spitting out each line one by one into my console as I NSLog them. I'm trying to feed each <game> into one of my Game objects, with name as an NSString, ID as an NSNumber, etc. However, I'm struggling to work out how I'd tell it to begin a new object, since the <game> tag isn't being returned in any of my NSLog statements, only those with actual data are (such as each name, id, etc.)
If I want to get all of the data within each <game> </game> tag into a separate object, how can I do so? Here's the parser code:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
element = [NSMutableString string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(#"ELEMENT TYPE: %# VALUE: %#", elementName, element);
}
First make yourself a Game class. We will parse the XML into Games objects.
Game.h like so:
#interface Game : NSObject
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSNumber *gameID;
#property (nonatomic, retain) NSString *gameDescription;
#end
Now in the class you are parsing the XML in (in this example ViewController), create a NSMutableArray property to store the Game objects as we parse them, a Game property to use as we create new Game objects, a NSString property to store the current element we are parsing in the XML, and a property for the NSXMLParser instance we are using. Also make sure it conforms to the NSXMLParserDelegate protocol.
So the header ViewController.h:
#interface ViewController : UIViewController <NSXMLParserDelegate>
#property (nonatomic, retain) NSString *currentElement;
#property (nonatomic, retain) NSMutableArray *games;
#property (nonatomic, retain) Game *gameBeingParsed;
#property (nonatomic, retain) NSXMLParser *xmlParser;
#end
Now in the implementation ViewController.m we parse the XML:
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Make an NSMutableArray to put the parsed Game objects in
self.games = [NSMutableArray array];
// Get the XML data to parse
// We need it in an NSdata object
NSString *xmlString = #"<?xml version=\"1.0\" encoding=\"utf-8\"?><xml><game><name>First game title</name><id>12345</id><desc>A game..</desc></game><game><name>Second game title</name><id>67890</id><desc>Another game..</desc></game></xml>";
NSData *xmlData = [xmlString dataUsingEncoding:NSStringEncodingConversionAllowLossy];
// Set up an NSXMLParser to use
// Set the delegate and start parsing!
self.xmlParser = [[[NSXMLParser alloc] initWithData:xmlData] autorelease];
_xmlParser.delegate = self;
[_xmlParser parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
// If we have a <game> tag then we are starting to parse a new Game object
if ([elementName isEqualToString:#"game"]) {
self.gameBeingParsed = [[[Game alloc] init] autorelease];
}
// If not then we need to keep track of the element name so we know which property to set on the Game object
else {
self.currentElement = elementName;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
// If we have a closing </game> tag we are done parsing a Game so add it to the array
if ([elementName isEqualToString:#"game"]) {
[_games addObject:_gameBeingParsed];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Work out which element we have the characters for
// Then set the property of the Game object
if ([_currentElement isEqualToString:#"name"]){
_gameBeingParsed.name = string;
}
if ([_currentElement isEqualToString:#"id"]){
_gameBeingParsed.gameID = [NSNumber numberWithInt:[string intValue]];
}
if ([_currentElement isEqualToString:#"name"]){
_gameBeingParsed.gameDescription = string;
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser{
// We are done parsing XML
NSLog(#"Parsed %d Games", _games.count);
for (Game *game in _games) {
NSLog(#"%# : %# : %#", game.name, game.gameID, game.gameDescription);
}
}
After parsing has finished and we get a call back in parserDidEndDocument: At this point the _games property will be populated we instances of Games.

xml parsing run but no data displayed

This is the code of my app . The applications runs but there is no data displayed , can you help me to fix this problem ?
In .h file:
#interface MyData : NSObject <NSXMLParserDelegate> {
NSMutableString *currentElementValue;
User *user;
NSMutableArray *users;
}
-(MyData *) initXMLParser;
-(BOOL)parseDocumentWithData:(NSData *)data;
#property (nonatomic, retain) User *user;
#property (nonatomic, retain) NSMutableArray *users;
In .m file:
#implementation MyData
#synthesize user;
#synthesize users;
- (MyData *) initXMLParser {
[super init];
// init array of user objects
users = [[NSMutableArray alloc] init];
return self;
}
-(BOOL)parseDocumentWithData:(NSData *)data {
NSString * filePath = [[NSBundle mainBundle] pathForResource:#"Users" ofType:#"xml"];
data = [NSData dataWithContentsOfFile:filePath];
if (data == nil)
return NO;
// this is the parsing machine
NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithData:data];
// this class will handle the events
[xmlparser setDelegate:self];
[xmlparser setShouldResolveExternalEntities:NO];
// now parse the document
BOOL ok = [xmlparser parse];
if (ok == NO)
NSLog(#"error");
else
NSLog(#"OK");
[xmlparser release];
return ok;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:#"user"]) {
NSLog(#"user element found – create a new instance of User class...");
user = [[User alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentElementValue) {
// init the ad hoc string with the value
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
// append value to the ad hoc string
[currentElementValue appendString:string];
}
NSLog(#"Processing value for : %#", string);
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"users"]) {
// We reached the end of the XML document
return;
}
if ([elementName isEqualToString:#"user"]) {
// object to our user array
[users addObject:user];
// release user object
[user release];
user = nil;
} else {
[user setValue:currentElementValue forKey:elementName];
}
[currentElementValue release];
currentElementValue = nil;
}
#end
/* This is the code of my app . The applications runs but there is no data displayed , can you help me to fix this problem ? */
This is the code of my app . The application runs but there is no data displayed , can you help me to fix this problem ? I want to display data when parsing
Well if you are using the NSXML parser (objective-c) you will need to append the data from the parsing of the xml element, to a string. How are you planning to display the data from the xml file.
You can apply the same method from here:
Techno Buffalo RSS
And then change the values in the parser to your element values.

Setting NSString variables with NSXMLParser

I am using NSXMLParser to grab information from an online XML file. My goal is to have one class do the XML parsing and another class to implement the variables. Below is the code for my project:
Current.h & Current.m
#import <Foundation/Foundation.h>
#interface Current : NSObject {
NSString *curTempF;
IBOutlet NSTextField *textField;
}
#property (nonatomic, copy) NSString *curTempF;
- (void)displayOutlets:(id)sender;
#end
and
#import "Current.h"
#implementation Current
#synthesize curTempF;
- (void)awakeFromNib {
[self displayOutlets:self];
}
- (void)displayOutlets:(id)sender {
[textField setStringValue:curTempF];
}
#end
XmlParser.h & XmlParser.m
#import <Foundation/Foundation.h>
#interface XmlParser : NSObject <NSXMLParserDelegate> {
NSString *urlString;
NSURL *url;
NSMutableString *xmlString;
}
- (IBAction)fetchXML:(id)sender;
#end
and
#import "XmlParser.h"
#import "Current.h"
#implementation XmlParser
- (void)awakeFromNib {
[self fetchXML:self];
}
- (IBAction)fetchXML:(id)sender {
urlString = #"http://api.wunderground.com/api/***/conditions/q/28173.xml";
url = [NSURL URLWithString:urlString];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqual:#"temp_f"]) {
xmlString = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqual:#"temp_f"]) {
Current *cTempF = [[Current alloc] init];
[cTempF setCurTempF:xmlString];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
[xmlString appendString:string];
}
#end
When I run the program I am receiving an error about "Invalid parameter not satisfying: aString". It looks like the setStringValue for the IBOutlet is not working. Any suggestions?
I suspect that when you initialize the Current class with [[Current alloc] init], it is trying to populate the textField with the curTempF string. However, the curTempF string is not initialized yet at that point until you call [cTempF setCurTempF:xmlString].
One approach would be to not display outlets in the Current class:
- (void)awakeFromNib {
//[self displayOutlets:self];
}
Then, call the displayOutlets function in your parser:
if ([elementName isEqual:#"temp_f"]) {
Current *cTempF = [[Current alloc] init];
[cTempF setCurTempF:xmlString];
[cTempF displayOutlets:cTempF];
}
Alternately, you could keep your awakeFromNib code the same, but create an initWith method in your Current class, which may be cleaner:
- (id) initWithCurTemp:(NSString *)curTemp {
self = [super init];
if (self) {
self.curTempF = curTemp;
}
return self;
}
- (void)awakeFromNib {
[self displayOutlets:self];
}
Then, your parser code would look like:
if ([elementName isEqual:#"temp_f"]) {
Current *cTempF = [[Current alloc] initWithCurTemp:xmlString];
}
You should create your Current in the nib, as you were doing, and not in code.
As for getting the parser (which I assume is in the same nib) to talk to the Current, create an outlet in the parser to point to the Current, and connect that outlet in the nib.

Simple and concise desktop Cocoa NSXMLParser example?

I would like to look through the elements of a file and when one specific element comes out, output the contents in between the tag.
I tried to follow the example in the Mac Dev entitled Event Driven XML Programming, but it just doesn't finish very clearly. It says to make sure I code the delegates, but it never shows an example. I just want to see a simple example where:
The file is assumed to be a good xml file.
Its path is a URL (or string).
The way the delegate interacts with the parser is explained.
Many tutorials for Cocoa seem to almost teach you to circumvent the delegate classes and make your own IBAction functions so I'm missing the training I think on how to use the delegates properly. Its not clear in the example if I'm supposed to build the delegates in the delegate class or keep them in the class with the parser.
This is based on something I originally wrote for Cut out a part of a long NSString. I copied the NSXMLParserDelegate code from that iOS project into an OS X project. It gets the text from a specific object in a web page.
.h file:
#interface so7576593AppDelegate : NSObject <NSApplicationDelegate, NSXMLParserDelegate> {
NSWindow *window;
IBOutlet NSTextField *textField;
NSMutableString *divCharacters;
BOOL captureCharacters;
}
#property (assign) IBOutlet NSWindow *window;
#end
.m file:
#import "so7576593AppDelegate.h"
#implementation so7576593AppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
captureCharacters = NO;
NSURL *theURL = [NSURL URLWithString:#"http://maxnerios.yolasite.com/"];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:theURL];
[parser setDelegate:self];
[parser parse];
[parser release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqual:#"div"] && [[attributeDict objectForKey:#"id"] isEqual:#"I3_sys_txt"]) {
captureCharacters = YES;
divCharacters = [[NSMutableString alloc] initWithCapacity:500];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (captureCharacters) {
//from parser:foundCharacters: docs:
//The parser object may send the delegate several parser:foundCharacters: messages to report the characters of an element.
//Because string may be only part of the total character content for the current element, you should append it to the current
//accumulation of characters until the element changes.
[divCharacters appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (captureCharacters) {
captureCharacters = NO;
[textField setStringValue:divCharacters];
[divCharacters release];
}
}
#end
If you click the "Next" link on that page and go onto "Handling XML Elements and Attributes" it will give you an example of how to code the delegates.
Apple provides a Mac example in ImageMap.
There's no difference between NSXMLParser on Mac and iPhone, so reading an iPhone example shouldn't be a problem.
Here is an example of using an NSXMLParser in a custom class that takes in a string of the tag to look for and the xml NSData:
JHXMLParser.h:
#protocol JHXMLParserDelegate <NSObject>
#optional
- (void)acceptParsedData:(NSMutableArray *)parsedData withIdent:(NSString *)ident;
- (void)acceptParsedDebugData:(NSMutableArray *)parsedData withIdent:(NSString *)ident;
#end
#class JHKeyValuePair;
#interface JHXMLParser : NSObject <NSXMLParserDelegate> {
NSString *ident;
#private
id _delegate;
NSMutableArray *_parsedData;
NSString *_key;
NSData *_rawData;
NSXMLParser *_dataParser;
NSString *_previousTag;
NSString *_currentTag;
}
#property (retain, nonatomic) NSString *ident;
- (id)initWithKeyValuePair:(JHKeyValuePair *)kvPair;
- (id)initWithKey:(NSString *)Key andData:(NSData *)data;
// delegate management. The delegate is not retained.
- (id <JHXMLParserDelegate>)delegate;
- (void)setDelegate:(id <JHXMLParserDelegate>)delegate;
- (BOOL)start;
#end
And the JHXMLParser.m:
#import "JHKeyValuePair.h"
#import "JHXMLParser.h"
#implementation JHXMLParser
#synthesize ident;
- (id)init {
if ((self = [super init])) {
ident = [[NSString alloc] init];
}
return self;
}
- (id)initWithKeyValuePair:(JHKeyValuePair *)kvPair {
if ((self = [self init])) {
_key = [kvPair key];
_rawData = [kvPair value];
_dataParser = [[NSXMLParser alloc] initWithData:_rawData];
_dataParser.delegate = self;
}
return self;
}
- (id)initWithKey:(NSString *)key andData:(NSData *)data {
if ((self = [self init])) {
_key = key;
_rawData = data;
_dataParser = [[NSXMLParser alloc] initWithData:_rawData];
_dataParser.delegate = self;
}
return self;
}
- (id <JHXMLParserDelegate>)delegate {
id <JHXMLParserDelegate> d = nil;
if (_delegate) {
d = _delegate;
}
return d;
}
- (void)setDelegate:(id <JHXMLParserDelegate>)delegate {
_delegate = delegate;
}
- (BOOL)start {
return [_dataParser parse];
}
- (void)dealloc {
[_parsedData release];
[_rawData release];
[super dealloc];
}
#pragma mark - NSXMLParser Delegate
- (void)parserDidStartDocument:(NSXMLParser *)parser {
_parsedData = [[NSMutableArray alloc] init];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
_currentTag = elementName;
if ([elementName isEqualToString:_key]) {
NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] init];
[_parsedData addObject:tmpDict];
[tmpDict release];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (![_previousTag isEqualToString:_currentTag]) {
[[_parsedData lastObject] setObject:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
forKey:_currentTag];
} else {
[[_parsedData lastObject] setObject:[NSString stringWithFormat:#"%#%#",[[_parsedData lastObject] objectForKey:_currentTag], [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]
forKey:_currentTag];
}
if (_previousTag) {
[_previousTag release];
_previousTag = nil;
}
_previousTag = [[NSString alloc] initWithFormat:#"%#", _currentTag];
[pool drain];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (![_previousTag isEqualToString:elementName]) {
[[_parsedData lastObject] setObject:#"" forKey:elementName];
} else {
if (_previousTag) {
[_previousTag release];
_previousTag = nil;
}
_previousTag = [[NSString alloc] initWithFormat:#""];
}
[pool drain];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
if ([_delegate respondsToSelector:#selector(acceptParsedData:withIdent:)]) {
[_delegate acceptParsedData:_parsedData withIdent:ident];
} else if ([_delegate respondsToSelector:#selector(acceptParsedDebugData:withIdent:)]) {
[_delegate acceptParsedDebugData:_parsedData withIdent:ident];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
#ifdef DEBUG
DEBUGLOG(#"Parser ERROR Occurred: %#", self.ident);
DEBUGLOG(#"ERROR: %#", parseError);
#endif
if ([_delegate respondsToSelector:#selector(acceptParsedData:withIdent:)]) {
[_delegate acceptParsedData:_parsedData withIdent:ident];
} else if ([_delegate respondsToSelector:#selector(acceptParsedDebugData:withIdent:)]) {
[_delegate acceptParsedDebugData:_parsedData withIdent:ident];
}
}
#end
Used like so:
parser = [[[JHXMLParser alloc] initWithKey:#"INFO" andData:connectData] autorelease];
parser.ident = #"INFO";
parser.delegate = self;
[parser start];
Then implement the delegate method:
- (void)acceptParsedData:(NSMutableArray *)parsedData withIdent:(NSString *)ident {
// do stuff here with the parsed data
}

Passing NULL value

I use an instance of NSXMLParser. I store found chars in NSMutableStrings that are stored in an NSMutableDictionary and these Dicts are then added to an NSMutableArray.
When I test this everything seems normal: I count 1 array, x dictionnaries and x strings.
In a detailview controller file I want to show my parsed results. I call the class where everthing is stored but I get (null) returned.
This is what I do (wrong):
xAppDelegate.h
#interface xAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
xAppDelegate.m
#import "xAppDelegate.h"
#import "RootViewController.h"
#import "XMLParser.h"
#implementation xAppDelegate
#synthesize window, navigationController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// OFFLINE DOCUMENT > Resources folder
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *DataPath = [Path stringByAppendingPathComponent:#"file.xml"];
NSData *Data = [[NSData alloc] initWithContentsOfFile:DataPath];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:Data];
XMLParser *parser = [[XMLParser alloc] initXMLParser];
[xmlParser setDelegate:parser];
[xmlParser setShouldProcessNamespaces:NO];
[xmlParser setShouldReportNamespacePrefixes:NO];
[xmlParser setShouldResolveExternalEntities:NO];
[xmlParser parse];
[window addSubview: navigationController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[window release];
[navigationController release];
[super dealloc];
}
#end
XMLParser.h
#class xAppDelegate;
#interface XMLParser : NSObject {
NSMutableArray *array;
NSMUtableDictionary *dictionary;
NSSMutabletring *element;
xAppDelegate *appDelegate;
}
- (XMLParser *) initXMLParser;
#property (nonatomic, retain) NSMutableArray *array;
#property (nonatomic, retain) NSMutableDictionary *dictionary;
#property (nonatomic, retain) NSMutableString *element;
XMLParser.m
#import "xAppDelegate.h"
#import "XMLParser.h"
#synthesize array, dictionary, element;
- (XMLParser *) initXMLParser {
[super init];
appDelegate = (xAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parserDidStartDocument:(NSXMLParser *)parser {
array = [[NSMutableArray alloc] init];
dictionary = [[NSMutableDictionary alloc] init];
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
ele = [elementName copy];
if ([elementName isEqualToString:#"CONTAINER"]) {
element = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSMutableString *)string
{
if ([ele isEqualToString:#"ELEMENTNAME"]) {
[element appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"CONTAINER"]) {
[dictionary setObject:element forKey:#"ELEMENTNAME"];
[array addObject:[dictionary copy]];
}
}
- (void) dealloc {
[element release];
[dictionary release];
[array release];
}
In my controller file I do this:
controller.h
#class XMLParser;
#interface controller : UIViewController {
XMLParser *aXMLParser;
}
#property (nonatomic, retain) XMLParser *aXMLParser;
controller.m
#import "XMLParser.h"
#synthesize aXMLParser;
- (void)viewDidLoad {
NSLog(#"test array: %#", aXMLParser.array);
NSLog(#"test dict: %#", aXMLParser.dictionary);
NSLog(#"test element: %#", aXMLParser.element);
}
When I test the value of my array, a dict or an element in the XMLParser.h file I get my result. What am I doing wrong so I can't call my results in my controller file?
Any help is welcome, because I'm pretty stuck right now :/
You probably haven't initialised the NSMutableString element, so you are probably sending messages to a nil object.
That's a guess because you haven't posted the important code. We need to see
where you initialise the three objects
where you assign them e.g. you might be assigning nil to one of them without realising it.
Edited following latest bit of code
There's quite a lot wrong with the code, for instance, it leaks a lot of objects, but I can't see anything that would cause your specific issue, unless the the ELEMENTNAME elements don't appear inside the CONTAINER elements in your XML.
I'm not an expert on user interface code on iPhone, but are you sure applicationDidFinishLaunching runs before viewDidLoad?
Also, you don't seem to ever assign your parser to the aXMLParser property.
Some of the Other Issues
Your NSXMLParser leaks because you don't release it.
Your own parser also leaks for the same reason (you probably just want to use aXMLParser, not a locally defined one).
Your initXMPLarser method should look like:
- (XMLParser *) initXMLParser {
self = [super init];
if (self != nil)
{
appDelegate = (xAppDelegate *)[[UIApplication sharedApplication] delegate];
}
return self;
}
i.e. don't throw away the result of [super init] and make sure it is not nil.
array is allocated every time you hit a new element. Each tilme you hit a new element, you throw away and leak the previous array from the last element.
dictionary is allocated every time you hit a CONTAINER element. You should at least release the old one before allocating the new one.
element also leaks.
The copy of dictionary you put into the array also leaks. Objective-C collections retain their elements.