NSMutableArray loses data - objective-c

There is lots of help regarding this issue already here but none of the implementations have worked. i.e.: creating (nonatomic, retain) + using self.myArray, Using a dictionary instead of arrays.
What I am doing is parsing information from an xml document, filter out unwanted entries, and try to dynamically store the information for that entry.
When I try to store the info into 2 mutableArrays the information of ONE of them gets lost when trying to access the info outside of my 'parser' method.
Some background code. Not full code. (this also has the dictionary as well)
.h
#interface WikiView : UIViewController {
//scrollview
UIScrollView *ScrollView;
//init
int isIpad;
int orientation;
int parseCount;
//parse data constructs
NSString *subplant;
NSString *element;
NSMutableString *text;
NSString *oldElement;
NSMutableDictionary *dataHolder;
NSMutableArray *dataGroup;
NSMutableArray *dataText;
}
#end
.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
//inits
dataGroup = [[NSMutableArray alloc] init];
dataText = [[NSMutableArray alloc] init];
dataHolder = [[NSMutableDictionary alloc] initWithCapacity:1];
text = [[NSMutableString alloc] init];
//parse the info
[self loadDataFromXML:xmlpath];
//When I call the values for dataText here they are all null
//also when called the objects for dataHolder are null as well
//this outputs the correct array
for (int i = 0; i<[dataGroup count]; i++) {
NSLog(#"%#",dataGroup[i]);
}
//this outputs an array of null objects
for (int i = 0; i<[dataText count]; i++) {
NSLog(#"HI.....%#",dataText[i]);
}
}
//parse function
//method to retrieve data
- (void)loadDataFromXML:(NSString *)xmlpath {
//data is parsed
NSData* data = [NSData dataWithContentsOfFile: xmlpath];
NSXMLParser* parser = [[NSXMLParser alloc] initWithData: data];
[parser setDelegate:self];
[parser parse];
[parser release];
}
//on found characters
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([subplant isEqualToString:plantid]) {
NSString *s2 = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (![oldElement isEqualToString:element]) {
if (oldElement != nil) {
if (parseCount >= 1) {
//Here I store the values into the proper places
NSLog(#"%#: %#",oldElement,text);
[dataGroup addObject:oldElement];
[dataText addObject:text];
[dataHolder setObject:text forKey:oldElement];
//The values are correct here
}
parseCount++;
}
//if (new tag) reset string
[text setString:s2];
}
else{
//if not new tag append string (takes care of &apos;)
[text appendString:s2];
}
oldElement = element;
}
}
//on did start element
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
//accessing tags of this element
if ([elementName isEqualToString:#"plant"]) {
subplant = [attributeDict valueForKey:#"plant"];
}
element = elementName;
}
-(void)dealloc{
[super dealloc];
[text release]; [dataGroup release]; [dataText release]; [dataHolder release];
}
I create dataGroup and dataText the exact same way but only dataText loses its value.
Any help is appreciated, and if any part of my code is unclear please let me know.
EDIT:
Found the source of the problem.
When I write to the dataText array I rewrite every entry to be the last entry to be entered. In my test case the last entry was the string #"null" creating an array of nulls.
Will be back with solution when found.
EDIT2:
#RuslanSoldatenko Noticed I did not create a new instance of my text string after I set the object in the array. Look at the comments for help.

Related

iOS - parse xml DATASET

This is my XML data that I need to parse
<GetMessagesResult>
<NewDataSet xmlns="">
<Table>
<Date>21:52:59</Date>
<Message>ABC</Message>
<GroupName>ALL</GroupName>
</Table>
<Table>
<Date>11:23:27</Date>
<Message>DEF</Message>
<GroupName>ALL</GroupName>
</Table>
</NewDataSet>
</GetMessagesResult>
This is my SCMessages.h file
#import <Foundation/Foundation.h>
#interface SCMessages : NSObject
{
NSDate *Date;
NSString *Message;
NSString *GroupName;
}
#property (nonatomic, retain) NSDate *Date;
#property (nonatomic, retain) NSString *Message;
#property (nonatomic, retain) NSString *GroupName;
and this is my SCMessages.m file
#import "SCMessages.h"
#implementation SCMessages
#synthesize Date;
#synthesize Message,GroupName;
- (void)dealloc
{
[super dealloc];
[Date release];
[Message release];
[GroupName release];
}
#end
I used below code to parse the data using NSXMLParser delegate methods
#pragma mark - NSXMLParser Delegate
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
attributes: (NSDictionary *)attributeDict
{
if( [elementName isEqualToString:#"GetMessagesResult"])
{
if(!soapResults)
soapResults = [[NSMutableString alloc] init];
recordResults = TRUE;
}
if([elementName isEqualToString:#"NewDataSet"]) {
//Initialize the array.
messages = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Table"]) {
//Initialize the message.
aMessage = [[SCMessages alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if( recordResults )
[soapResults appendString: string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"Table"]) {
[messages addObject:aMessage];
NSLog(#"MESSAGES COUNT: %d",messages.count);
NSLog(#"MESSAGE: %#",aMessage);
[aMessage release];
aMessage = nil;
}
// as this is the last element
if( [elementName isEqualToString:#"NewDataSet"])
{
recordResults = FALSE;
}
}
PROBLEM I am not getting the desired message object with Date, Meesage & GroupName.
I put NSLog to print them but I always get null value. The weird thing is message array gets allocated memory & also elements gets added to array as I can see message array count in NSLog but the array element has data as null value.
I am parsing the XML data received in SOAP response in NSURLConnection delegate method connectionDidFinishLoading
NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
NSLog(#"theXML: \n%#",theXML);
You need to store your values in aMessage. You have added particular object to array but you forgot to store data in that object of SCMessages class.You can also check while debug that you are getting value in aMessage object.
You need to store value like this in this didEndElement method.
[aMessage setValue: soapResults forKey:elementName];
I think this will help you.
Your didEnd method is missing code to store the accumulated string into a property. You need an ivar for the current SCMessage object.
Append text content to a mutable string ivar. Then on closing an element you have to decide which property to set on SCMessage. You probably have to parse the date into an NSDate.

Xml to dictionary parsing using XML reader [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I want to convert data in to dictionary ,any suggestions..
if you are newbie and don't know how to parse xml to dictionary... try with the below methods...
in .h file add this methods
#import <Foundation/Foundation.h>
#interface XMLReader : NSObject
{
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError **errorPointer;
}
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)errorPointer;
#end
and in your .m file parse your URL using these methods.
NSString *const kXMLReaderTextNodeKey = #"text";
#interface XMLReader (Internal)
- (id)initWithError:(NSError **)error;
- (NSDictionary *)objectWithData:(NSData *)data;
#end
#implementation XMLReader
#pragma mark -
#pragma mark Public methods
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)error
{
XMLReader *reader = [[XMLReader alloc] initWithError:error];
NSDictionary *rootDictionary = [reader objectWithData:data];
[reader release];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [XMLReader dictionaryForXMLData:data error:error];
}
#pragma mark -
#pragma mark Parsing
- (id)initWithError:(NSError **)error
{
if (self = [super init])
{
errorPointer = error;
}
return self;
}
- (void)dealloc
{
[dictionaryStack release];
[textInProgress release];
[super dealloc];
}
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
[dictionaryStack release];
[textInProgress release];
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
BOOL success = [parser parse];
// Return the stack's root dictionary on success
if (success)
{
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element, and initilaize it with the attributes
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
[childDict addEntriesFromDictionary:attributeDict];
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue)
{
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]])
{
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else
{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else
{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Set the text property
if ([textInProgress length] > 0)
{
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
// Reset the text
[textInProgress release];
textInProgress = [[NSMutableString alloc] init];
}
// Pop the current dict
[dictionaryStack removeLastObject];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:string];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
// Set the error pointer to the parser's error object
*errorPointer = parseError;
}
#end
I think this would be helpful to you for parsing the xml data.

nsmutablearray elements to nsstring

I want to retrieve elements that are parsed in a NSMutableArray and store them into a NSString variable and then store them in NSMutableArray as NSString (because I want to display the content in a NSComboBox). I tried this but it dosen't work. Can you fix the problem, I can't fix it:
//--this is the parsing code :
- (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...");
if(currentElementValue == nil)
currentElementValue = [NSMutableString string];
else
[currentElementValue setString:#""];
}
else {
currentElementValue = nil;
}
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];
if (currentElementValue)
{
currentElementValue = nil;
}
}
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;
NSLog(#"QUIT");
}
if ([elementName isEqualToString:#"userName"]) {
[[self user] setUserName:currentElementValue];
NSLog(#"final step for value: %#", user.userName);
NSLog(#"currentElementName content : %#", currentElementValue);
[currentElementValue release];
NSLog(#"release : %#", currentElementValue);
currentElementValue = nil;
NSLog(#"release : %#", currentElementValue);
}
if ([elementName isEqualToString:#"firstName"]) {
[[self user] setFirstName:currentElementValue];
[currentElementValue release];
currentElementValue = nil;
}
if ([elementName isEqualToString:#"lastName"]) {
[[self user] setLastName:currentElementValue];
[currentElementValue release];
currentElementValue = nil;
}
if ([elementName isEqualToString:#"user"]) {
NSLog(#"\n user=%# \n",user);
[users addObject:user];
NSLog(#"userName test : %#", users);
[user release];
user = nil;
}
}
-(BOOL)parseDocumentWithData:(NSData *)data {
if (data == nil)
return NO;
NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithData:data];
[xmlparser setDelegate:self];
[xmlparser setShouldResolveExternalEntities:NO];
BOOL ok = [xmlparser parse];
if (ok == NO)
NSLog(#"error");
else
NSLog(#"OK");
[xmlparser release];
return ok;
}
// this is the xml file :
<users>
<user>
<userName>mspeller</userName>
<firstName>Mike</firstName>
<lastName>Speller</lastName>
</user>
<user>
<userName>mgdan</userName>
<firstName>Mila</firstName>
<lastName>Gdan</lastName>
</user>
</users>
//-------
NSMutableArray *tabletest= [[NSMutableArray alloc] init];
NSMutableString * result = [[NSMutableString alloc] init];
int i;
for(i=0; i < [users count]; i++){
[result appendString:[NSString stringWithFormat:#"%#",[[users objectAtIndex:i] valueForKey:#"userName"]] ];
NSLog(#"result==%#",result);
[tabletest addObject:result];
}
Based on your link in the comment section I think you're accessing the "userName" property the wrong way. You're trying to access it, as users contains NSDictionary objects. As far as I can see you're adding User objects to the NSMutableArray.
Try the following (I took the liberty to beautify the code a bit):
NSMutableArray *tabletest= [NSMutableArray array];
for (User* user in users)
{
NSString* result = [NSString stringWithFormat:#"%#", user.userName];
NSLog(#"result==%#",result);
[tabletest addObject:result];
}
Please correct me if I totally misunderstood your design.
I don't follow what your intention is, but what your code does at the moment is add the same string [user count] time to the array tabletest as follows:
The line:
[result appendString:[NSString stringWithFormat:#"%#",[[users objectAtIndex:i] valueForKey:#"userName"]] ];
accumulates into result the result of appending each [[users objectAtIndex:i] valueForKey:#"userName"] together - each iteration of the loop adds the next item to the end of result.
The line:
[tabletest addObject:result];
Adds the object referenced by result into the array. This is done once per iteration so the array ends up with [users count] references to the same object. Placing a reference to a mutable string into an array does not place a copy of its current value, just a reference to the string - mutate the string and the mutation is visible through the reference stored in the array.
So the final result of your code is an array of [users count] references to the same mutable string, and that string is the concatenation of all the [[users objectAtIndex:i] valueForKey:#"userName"] values.
What was your intent?
If you are trying to create an array of string representations of [[users objectAtIndex:i] valueForKey:#"userName"] then change the code to:
NSMutableArray *tabletest= [[NSMutableArray alloc] init];
for(int i = 0; i < [users count]; i++)
{
// create a string representation of userName
NSString *result = [NSString stringWithFormat:#"%#",[[users objectAtIndex:i] objectForKey:#"userName"]];
// add the string to the array
[tabletest addObject:result];
}
But maybe your intent is something else?

Parsing NSXMLNode Attributes in Cocoa

Given the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<application name="foo">
<movie name="tc" english="tce.swf" chinese="tcc.swf" a="1" b="10" c="20" />
<movie name="tl" english="tle.swf" chinese="tlc.swf" d="30" e="40" f="50" />
</application>
How can I access the attributes ("english", "chinese", "name", "a", "b", etc.) and their associated values of the MOVIE nodes? I currently have in Cocoa the ability to traverse these nodes, but I'm at a loss at how I can access the data in the MOVIE NSXMLNodes.
Is there a way I can dump all of the values from each NSXMLNode into a Hashtable and retrieve values that way?
Am using NSXMLDocument and NSXMLNodes.
YES! I answered my own question somehow.
When iterating through the XML document, instead of assigning each child node as an NSXMLNode, assign it as an NSXMLElement. You can then use the attributeForName function, which returns an NSXMLNode, to which you can use stringValue on to get the attribute's value.
Since I'm bad at explaining things, here's my commented code. It might make more sense.
//make sure that the XML doc is valid
if (xmlDoc != nil) {
//get all of the children from the root node into an array
NSArray *children = [[xmlDoc rootElement] children];
int i, count = [children count];
//loop through each child
for (i=0; i < count; i++) {
NSXMLElement *child = [children objectAtIndex:i];
//check to see if the child node is of 'movie' type
if ([child.name isEqual:#"movie"]) {
{
NSXMLNode *movieName = [child attributeForName:#"name"];
NSString *movieValue = [movieName stringValue];
//verify that the value of 'name' attribute of the node equals the value we're looking for, which is 'tc'
if ([movieValue isEqual:#"tc"]) {
//do stuff here if name's value for the movie tag is tc.
}
}
}
}
There are two options. If you continue to use NSXMLDocment and you have an NSXMLNode * for the a movie element, you can do this:
if ([movieNode kind] == NSXMLElementKind)
{
NSXMLElement *movieElement = (NSXMLElement *) movieNode;
NSArray *attributes = [movieElement attributes];
for (NSXMLNode *attribute in attributes)
{
NSLog (#"%# = %#", [attribute name], [attribute stringValue]);
}
}
Otherwise, you can switch to using an NSXMLParser instead. This is an event driven parser that informs a delegate when it has parsed elements (among other things). The method you're after is parser:didStartElement:namespaceURI:qualifiedName:attributes:
- (void) loadXMLFile
{
NSXMLParser *parser = [NSXMLParser parserWithContentsOfURL:#"file:///Users/jkem/test.xml"];
[parser setDelegate:self];
[parser parse];
}
// ... later ...
- (void) parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"movie"])
{
NSLog (#"%#", [attributeDict objectForKey:#"a"]);
NSLog (#"%d", [[attributeDict objectForKey:#"b"] intValue]);
}
}

Core Data with NSXMLParser on iPhone saving object incorrectly

I'm new to Objective-C, XCode and iPhone development in general and I'm having some issues with Core Data and NSXMLParser.
Having followed Apples' tutorials SeismicXML (for NSXMLParser) and the Core Data on iPhone tutorial I've ran into an issue when assigning values to my Managed Object Models' entities properties.
To explain the situation my code only varies from the SeismicXML example by using CoreData to assign the currentParsedCharacterData to my managed objects rather than the standard NSObject which the SeismicXML project uses.
Below is the description output from my managed object.
county = "-53.25354768,4.256547";
friendly = "-53.25354768,4.256547";
image = nil;
latitude = -53.253547684;
link = "-53.25354768,4.256547";
longitude = nil;
name = "-53.25354768,4.256547";
postcode = "-53.25354768,4.256547";
shopDescription = nil;
shopID = 0;
tag = "-53.25354768,4.256547";
tags = (
);
telephone = "-53.25354768,4.256547";
town = "-53.25354768,4.256547";
What appears to be happening is that all of the attributes/properties are assigned the value of the last node in my XML feed; which happens to be longitude, latitude. Yet when logging parsed character data at the time of the property assignment it is the expected (and correct) value but when outputting the description of this object all string values are wrong and number values/otherwise are simply 0 or nil.
Any suggestions would be extremely appreciated. If need be I can knock up a smaller project which shows this behaviour with the same XML feed that I am using.
EDIT:
Here is an abbreviated example of what I am doing to get information into the managed object which results in the same error.
For convenience sake I have a zip of the project http://willb.ro/CoreDataProblemExample.zip
Debug Output 2009-11-16 14:31:20.357
ShittyExample[4360:4d07] Company
Description:
(entity: Company; id: 0x3f6e9e0
; data: {
companyDescription = "Top Shop are a leading brandname in the retail
sec";
companyID = 66136112;
name = "Top Shop are a leading brandname in the retail sec"; })
//XML
<channel>
<company id="1">
<name>Top Shop</name>
<description>Top Shop are a leading brandname in the retail sector.</description>
</company>
</channel>
// FeedImporter.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class RootViewController, Company;
#interface FeedImporter : NSObject {
NSManagedObjectContext *managedObjectContext;
RootViewController *rootViewController;
NSMutableArray *companyList;
// for downloading the xml data
NSURLConnection *companyFeedConnection;
NSMutableData *companyData;
// these variables are used during parsing
Company *currentCompanyObject;
NSMutableArray *currentParseBatch;
NSUInteger parsedCompaniesCounter;
NSMutableString *currentParsedCharacterData;
BOOL accumulatingParsedCharacterData;
BOOL didAbortParsing;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) RootViewController *rootViewController;
#property (nonatomic, retain) NSMutableArray *companyList;
#property (nonatomic, retain) NSURLConnection *companyFeedConnection;
#property (nonatomic, retain) NSMutableData *companyData;
#property (nonatomic, retain) Company *currentCompanyObject;
#property (nonatomic, retain) NSMutableString *currentParsedCharacterData;
#property (nonatomic, retain) NSMutableArray *currentParseBatch;
- (void)parseFeed;
- (void)addCompaniesToList:(NSArray *)companies;
- (void)handleError:(NSError *)error;
#end
// FeedImporter.m
#import "FeedImporter.h"
#import "RootViewController.h"
#import <CFNetwork/CFNetwork.h>
#import "Company.h"
#implementation FeedImporter
#synthesize managedObjectContext;
#synthesize rootViewController;
#synthesize companyList;
#synthesize companyFeedConnection;
#synthesize companyData;
#synthesize currentCompanyObject;
#synthesize currentParseBatch;
#synthesize currentParsedCharacterData;
- (void)dealloc {
[super dealloc];
[managedObjectContext release];
[rootViewController release];
[companyList release];
[companyFeedConnection release];
[companyData release];
[currentCompanyObject release];
[currentParseBatch release];
[currentParsedCharacterData release];
}
- (id)init {
if(self = [super init]) {
// Custom loading logic goes here..
}
return self;
}
- (void)parseFeed {
static NSString *feedURLString = #"http://willb.ro/companies.xml";
NSURLRequest *companyURLRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURLString]];
self.companyFeedConnection = [[[NSURLConnection alloc] initWithRequest:companyURLRequest delegate:self] autorelease];
NSAssert(self.companyFeedConnection != nil, #"Failure to create URL connection.");
// Start the status bar network activity indicator. We'll turn it off when the connection finishes or experiences an error.
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
#pragma mark NSURLConnection delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.companyData = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[companyData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if ([error code] == kCFURLErrorNotConnectedToInternet) {
// if we can identify the error, we can present a more precise message to the user.
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedString(#"No Connection Error", #"Error message displayed when not connected to the Internet.") forKey:NSLocalizedDescriptionKey];
NSError *noConnectionError = [NSError errorWithDomain:NSCocoaErrorDomain code:kCFURLErrorNotConnectedToInternet userInfo:userInfo];
[self handleError:noConnectionError];
} else {
// otherwise handle the error generically
[self handleError:error];
}
self.companyFeedConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
self.companyFeedConnection = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[NSThread detachNewThreadSelector:#selector(parseCompanyData:) toTarget:self withObject:companyData];
self.companyData = nil;
}
- (void)parseCompanyData:(NSData *)data {
// You must create a autorelease pool for all secondary threads.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
self.currentParseBatch = [NSMutableArray array];
self.currentParsedCharacterData = [NSMutableString string];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];
if ([self.currentParseBatch count] > 0) {
[self performSelectorOnMainThread:#selector(addCompaniesToList:) withObject:self.currentParseBatch waitUntilDone:NO];
}
self.currentParseBatch = nil;
self.currentCompanyObject = nil;
self.currentParsedCharacterData = nil;
// Save to our MOC...
NSError *saveError;
if(![self.managedObjectContext save:&saveError]) {
// Handle MOM save error
NSLog(#"error while saving shop to managed object model");
NSError* error;
if(![[self managedObjectContext] save:&error]) {
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else {
NSLog(#" %#", [error userInfo]);
}
}
}
else
{
NSLog(#"MOC saved sucessfully");
}
[parser release];
[pool release];
}
#pragma mark Parser constants
// Limit the number of parsed companies to 50.
static const const NSUInteger kMaximumNumberOfCompaniesToParse = 50;
static NSUInteger const kSizeOfCompanyBatch = 10;
static NSString * const kChannelElementName = #"channel";
static NSString * const kCompanyElementName = #"company";
static NSString * const kCompanyNameElementName = #"name";
static NSString * const kCompanyDescriptionElementName = #"description";
- (void)addCompaniesToList:(NSArray *)companies {
[self.companyList addObjectsFromArray:companies];
// The table needs to be reloaded to reflect the new content of the list.
[rootViewController.tableView reloadData];
}
#pragma mark NSXMLParser delegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if (parsedCompaniesCounter >= kMaximumNumberOfCompaniesToParse) {
didAbortParsing = YES;
[parser abortParsing];
}
if ([elementName isEqualToString:kCompanyElementName]) {
Company *company = (Company *)[NSEntityDescription insertNewObjectForEntityForName:#"Company" inManagedObjectContext:self.managedObjectContext];
self.currentCompanyObject = company;
[company release];
int companyIDInt = (int)[attributeDict valueForKey:#"id"];
NSNumber *companyID = [NSNumber numberWithInt:companyIDInt];
[self.currentCompanyObject setCompanyID:companyID];
}
else if ([elementName isEqualToString:kCompanyElementName] || [elementName isEqualToString:kCompanyNameElementName] || [elementName isEqualToString:kCompanyDescriptionElementName]) {
accumulatingParsedCharacterData = YES;
[currentParsedCharacterData setString:#""];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:kCompanyElementName]) {
//NSLog(#"currentEarthquakeObject: %#", currentEarthquakeObject);
[self.currentParseBatch addObject:self.currentCompanyObject];
parsedCompaniesCounter++;
if (parsedCompaniesCounter % kSizeOfCompanyBatch == 0) {
[self performSelectorOnMainThread:#selector(addCompaniesToList:) withObject:self.currentParseBatch waitUntilDone:NO];
self.currentParseBatch = [NSMutableArray array];
}
//NSLog(#"Reached end of company. Follows is a description of our company object: %#", [self.currentCompanyObject description]);
NSLog(#"Company Description: %#", [self.currentCompanyObject description]);
}
else if ([elementName isEqualToString:kCompanyNameElementName]) {
// Company Name
[self.currentCompanyObject setName:self.currentParsedCharacterData];
//NSLog(#"%#",self.currentParsedCharacterData);
}
else if ([elementName isEqualToString:kCompanyDescriptionElementName]) {
// Company Description
[self.currentCompanyObject setCompanyDescription:self.currentParsedCharacterData];
//NSLog(#"%#",self.currentParsedCharacterData);
}
accumulatingParsedCharacterData = NO;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (accumulatingParsedCharacterData) {
[self.currentParsedCharacterData appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
if (didAbortParsing == NO) {
[self performSelectorOnMainThread:#selector(handleError:) withObject:parseError waitUntilDone:NO];
}
}
- (void)handleError:(NSError *)error {
NSString *errorMessage = [error localizedDescription];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Error Title", #"Title for alert displayed when download or parse error occurs.") message:errorMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
[alertView release];
}
#end
It seems you are assigning where you ought to be copying. I'd have to see more of your code to be sure, but I'm almost certain a copy somewhere would solve your issues.
As stated above, i had the exact same problem. But would now recommend to bypass the useless NSXMLParser (if using it WITH core data!!!) and using GDataXML instead. GDataXML is modelled on the NSXMLDocument class (which is a more elegant and workable solution to use with core data, only that you can't use NSXMLDocument with iOS).
See here for an excellent tutorial:
http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml
:)