NSXMLParser multiple call - BAD ACCESS - iphone

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 :)

Related

xcode 4.2 Loop Through XML Data Elements

I am very confused on how I am supposed to loop through XML elements for my current iPhone app project. I will show my code, then clarify my question.
Here is sample XML I am using:
<restaurant_details>
<total_results>90</total_results>
<restaurant>
<name>Through the Garden</name>
<distance_from_current_location>0.55</distance_from_current_location>
<restaurant_id>123</restaurant_id>
<longitude>-84.373734</longitude>
<latitude>39.258606</latitude>
<address>10738 Kenwood Rd | cincinnati ,OH | 45242</address>
<phone_number>513-791-2199</phone_number>
<restaurant_type>General</restaurant_type>
</restaurant>
</restaurant_details>
Getting data for my table:
- (void)get_table_data {
NSString *day = [self dateInFormat:#"%A"];
NSLog (#"At get_table_data");
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.url.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
NSLog (#"At connection");
receivedData = [NSMutableData data];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
// NSString *theXML = [[NSString alloc] initWithBytes: [myWebData mutableBytes] length:[myWebData length] encoding:NSUTF8StringEncoding];
// NSLog(#"%#",theXML);[theXML release];
if(parser){
parser = nil;
}
parser = [[NSXMLParser alloc] initWithData: receivedData];
[parser setDelegate: self];
[parser setShouldResolveExternalEntities: YES];
[parser parse];
}
And my parser code:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict{
NSLog (#"At parser");
currentElement = elementName;
if ([currentElement isEqualToString:#"restaurant_details"]) {
if ([currentElement isEqualToString:#"total_results"]) {
//NSLog(#"Element: %#", currentElement);
}else if ([currentElement isEqualToString:#"restaurant"]) {
restaurantObj = [[DOR_RestaurantClass alloc]init];
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if([currentElement isEqualToString:#"name"]) {
restaurantObj.name=[NSString stringWithFormat:#"%#",string];
//NSLog(#"Name to be saved in Array :- %#",string);
}
if([currentElement isEqualToString:#"distance_from_current_location"]) {
restaurantObj.distance=[NSString stringWithFormat:#"%#",string];
//NSLog(#"Name to be saved in Array :- %#",string);
}
if([currentElement isEqualToString:#"restaurant_id"]) {
restaurantObj.restId=[NSString stringWithFormat:#"%#",string];
//NSLog(#"Name to be saved in Array :- %#",string);
}
if([currentElement isEqualToString:#"address"]) {
NSArray *stringArray = [string componentsSeparatedByString:#" | "];
restaurantObj.address=[stringArray objectAtIndex:0];
restaurantObj.address2=[stringArray objectAtIndex:1];
restaurantObj.address3=[stringArray objectAtIndex:2];
//NSLog(#"Name to be saved in Array :- %#",string);
}
if([currentElement isEqualToString:#"phone_number"]) {
restaurantObj.phone=[NSString stringWithFormat:#"%#",string];
//NSLog(#"Name to be saved in Array :- %#",string);
}
if([currentElement isEqualToString:#"description"]) {
restaurantObj.description=[NSString stringWithFormat:#"%#",string];
//NSLog(#"Name to be saved in Array :- %#",string);
}
if([currentElement isEqualToString:#"image_url"]) {
restaurantObj.image=[NSString stringWithFormat:#"%#",string];
//NSLog(#"Name to be saved in Array :- %#",string);
}
if([currentElement isEqualToString:#"restaurant_type"]) {
//restaurantObj.Name=[NSString stringWithFormat:#"%#",string];
//NSLog(#"Name to be saved in Array :- %#",string);
}
NSLog (#"At parser2");
if(!currentElementValue)
currentElementValue=[[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(#"the parser just found this text in a tag:%#",string);
}
-(void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName {
NSLog(#"Current element in End Element Category:- %#",currentElement);
if([elementName isEqualToString:#"restaurant"]) {
[listItems addObject:restaurantObj];
NSLog(#"Array: %#", listItems);
}else{
currentElementValue=nil;
}
}
Here's my .h for my restaurant class:
#import <Foundation/Foundation.h>
#interface DOR_RestaurantClass : NSObject
#property (nonatomic, retain) NSString *restId;
#property (nonatomic, retain) NSString *image;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *description;
#property (nonatomic, retain) NSString *distance;
#property (nonatomic, retain) NSString *address;
#property (nonatomic, retain) NSString *address2;
#property (nonatomic, retain) NSString *address3;
#property (nonatomic, retain) NSString *phone;
#property (nonatomic, retain) NSString *expires;
#end
And my .m:
#import "DOR_RestaurantClass.h"
#implementation DOR_RestaurantClass
#synthesize restId;
#synthesize image;
#synthesize name;
#synthesize description;
#synthesize distance;
#synthesize address;
#synthesize address2;
#synthesize address3;
#synthesize phone;
#synthesize expires;
#end
I am getting my data and so forth, so that's not an issue. My question is this: With multiple "restaurant" tags in my XML data, how do I sort through the XML so that I keep restaurant data together? I come from PHP, so I would have done a foreach on the restaurant tags, but I'm not sure how the NSXMLParser is supposed to keep the data seperated. I will be putting this information into an NSMutableArray in the end. I just don't know where to start, and cannot find any good examples on doing this. Any and all help is greatly appreciated.
This has been updated
My array listItems (NSMutableArray) is null when I print it to NSLog.
Firstly Create a Obj c class having .h and .m files only. and in that create some NSString Variables having properties like name, distance, longitude, latitude.. etc etc.
now, the code part :-
In didStartElement
in restaurant tag create a Object of that class which i just told u to create(initialize the Object):-
currentElement = elementName;
if([currentElement isEqualToString:#"restaurant"]) {
classObj = [[MyRestaurentClass alloc]init];
}
Now In foundCharacters find the other tags like this :-
if([currentElement isEqualToString:#"name"]) {
classObj.Name=[NSString stringWithFormat:#"%#",string];
NSLog(#"Name to be saved in Array :- %#",string);
}
if ( [currentElement isEqualToString:#"longitude"])
{
classObj.longitude =[NSString stringWithFormat:#"%#",string];
}
}
Now Last part in didEneElement :-
Create a MutubaleArray in Parser Class and Add the classObj in that array in didEndElement :-
if([elementName isEqualToString:#"restaurent"]) {
NSLog(#"Current element in End Element Category:- %#",currentElement);
[ObjectsMutableArray addObject:classObj];
}
And that's all. u r finished with parsing ..
UPDATE
Firstly you dont have to write like this in If loop i.e. :-
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict{
NSLog (#"At parser");
currentElement = elementName;
if ([currentElement isEqualToString:#"restaurant_details"]) {
if ([currentElement isEqualToString:#"total_results"]) {
//NSLog(#"Element: %#", currentElement);
}else if ([currentElement isEqualToString:#"restaurant"]) {
restaurantObj = [[DOR_RestaurantClass alloc]init];
}
}
}
What i wrote in answer for didStartElement is Sufficient as didStartElement is called for Each n Every Tag.
See Once u create a class having NSStrings acc to your XML. Just create an Object of that class and Initialize it in didStartElement.
in foundCharacters you will add the Required data in the classObject variables according to the If Conditions loops. Whenever the XMlParser comes in the </restaurent> Tag it will go in didEndElement method and there you just have to Put that classObject (object) in that Array like i did in didEndElement.
Ok Regarding your NSMutableArray, have you Initialized the Array in didStartDocument like this :-
(void)parserDidStartDocument:(NSXMLParser *)parser{
listItems = [[NSMutableArray alloc]init];
}
I have Changed a Above Code so please read again the whole answer carefully.
If u still have any doubts Text me...

Insert Managed Object into CoreData from xml

This is my first time trying to accomplish core data and been having some issues getting things working. I have a xml parser in my app that I have been trying to add all the info into core data from but keep crashing on start. I have my core data set up with 1 Entity as "Themes". In that entity I have 15 attributes. Below is the automatic file xcode can created for a ManagedObject after I created my .CoreData.
Themes.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Themes : NSManagedObject
#property (nonatomic, retain) NSString * themeName;
#property (nonatomic, retain) NSString * themeArtist;
#property (nonatomic, retain) NSString * themeImage;
#property (nonatomic, retain) NSString * themeDescription;
#property (nonatomic, retain) NSString * twitterName;
#property (nonatomic, retain) NSString * themePrice;
#property (nonatomic, retain) NSString * screenshots;
#property (nonatomic, retain) NSString * cydiaLink;
#property (nonatomic, retain) NSString * themeVersion;
#property (nonatomic, retain) NSString * deciption;
#property (nonatomic, retain) NSString * repo;
#property (nonatomic, retain) NSString * hd;
#property (nonatomic, retain) NSString * sd;
#property (nonatomic, retain) NSString * ipad;
#end
#import "Themes.h"
#implementation Themes
#dynamic themeName;
#dynamic themeArtist;
#dynamic themeImage;
#dynamic themeDescription;
#dynamic twitterName;
#dynamic themePrice;
#dynamic screenshots;
#dynamic cydiaLink;
#dynamic themeVersion;
#dynamic deciption;
#dynamic repo;
#dynamic hd;
#dynamic sd;
#dynamic ipad;
-(void)setThemeName:(NSString *)themeName{
self.themeName = [themeName copy];
}
#end
Here is my xml Parser files where all the magic is supposed to happen. Overall everything works great with my parser it is just when I do
"themesObjects = (Themes *)[NSEntityDescription
insertNewObjectForEntityForName:themesObjects.themeName"
inManagedObjectContext:managedObjectContext];"
the app will crash I assume because I am not correctly inserting the object into the coredata.
#import <Foundation/Foundation.h>
#import "ThemeParseObject.h"
#import "Themes.h"
#class ThemeParseObject;
#interface ThemeXMLParser : NSObject <NSXMLParserDelegate> {
NSMutableData *recivedData;
NSMutableArray *themes;
NSMutableString *currentNodeContent;
NSXMLParser *parser;
Themes *themesObjects;
NSManagedObjectContext *managedObjectContext;
NSMutableArray *themeArray;
ThemeParseObject *currentTheme;
}
#property (readonly, retain) NSMutableArray *themes;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSMutableArray *themeArray;
-(id) loadXMLByURL:(NSString *)urlString;
#end
#import "ThemeXMLParser.h"
#implementation ThemeXMLParser
#synthesize themes;
#synthesize managedObjectContext;
#synthesize themeArray;
-(id) loadXMLByURL:(NSString *)urlString{
themesObjects = [[Themes alloc]init];
managedObjectContext = [[NSManagedObjectContext alloc] init];
themes = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"theme"])
{
currentTheme = [ThemeParseObject alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *ObjectsToInsert = [NSEntityDescription
insertNewObjectForEntityForName:#"Themes"
inManagedObjectContext:context];
if ([elementName isEqualToString:#"name"]) {
currentTheme.themeNameString = currentNodeContent;
themesObjects.themeName = currentTheme.themeNameString;
[ObjectsToInsert setValue:themesObjects.themeName forKey:#"themeName"];
}
if ([elementName isEqualToString:#"creator"]) {
currentTheme.themeCreator = currentNodeContent;
// themesObjects = (Themes *)[NSEntityDescription
insertNewObjectForEntityForName:#"themeArtist"
inManagedObjectContext:managedObjectContext];
}
if ([elementName isEqualToString:#"price"]) {
currentTheme.themePrice = currentNodeContent;
//themesObjects = (Themes *)[NSEntityDescription
insertNewObjectForEntityForName:#"themePrice"
inManagedObjectContext:managedObjectContext];
}
if ([elementName isEqualToString:#"twitter"]) {
currentTheme.creatorTwitterName = currentNodeContent;
//themesObjects = (Themes *)[NSEntityDescription
insertNewObjectForEntityForName:#"twitterName"
inManagedObjectContext:managedObjectContext];
}
if ([elementName isEqualToString:#"link"]) {
currentTheme.cydiaLink = currentNodeContent;
//themesObjects = (Themes *)[NSEntityDescription
insertNewObjectForEntityForName:#"cydiaLink"
inManagedObjectContext:managedObjectContext];
}
if ([elementName isEqualToString:#"deciption"]) {
currentTheme.deciption = currentNodeContent;
//themesObjects = (Themes *)[NSEntityDescription
insertNewObjectForEntityForName:#"deciption"
inManagedObjectContext:managedObjectContext];
}
if ([elementName isEqualToString:#"screenshots"]) {
currentTheme.screenShots = currentNodeContent;
}
if ([elementName isEqualToString:#"promo"]) {
currentTheme.tblViewImage = currentNodeContent;
}
if ([elementName isEqualToString:#"description"]) {
currentTheme.themeDescription = currentNodeContent;
}
if ([elementName isEqualToString:#"version"]) {
currentTheme.themeVersion = currentNodeContent;
// NSLog(#"version: %#", currentNodeContent);
}
if ([elementName isEqualToString:#"repo"]) {
currentTheme.themeRepo = currentNodeContent;
// NSLog(#"repo: %#", currentNodeContent);
}
if ([elementName isEqualToString:#"HD"]) {
currentTheme.HD = currentNodeContent;
// NSLog(#"HD: %#", currentNodeContent);
}
if ([elementName isEqualToString:#"SD"]) {
currentTheme.SD = currentNodeContent;
// NSLog(#"SD: %#", currentNodeContent);
}
if ([elementName isEqualToString:#"iPad"]) {
currentTheme.ipad = currentNodeContent;
//NSLog(#"iPad: %#", currentNodeContent);
}
if ([elementName isEqualToString:#"iPhoneScreenshots"]) {
currentTheme.fullScreenShots = currentNodeContent;
// themesObjects = (Themes *)[NSEntityDescription
insertNewObjectForEntityForName:#"screenshots"
inManagedObjectContext:managedObjectContext];
// NSLog(#"fullScreenShots: %#", currentNodeContent);
}
if ([elementName isEqualToString:#"theme"])
{
[themes addObject:currentTheme];
[currentTheme release];
currentTheme = nil;
[currentNodeContent release];
currentNodeContent = nil;
}
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
This is what gets logged when the app crashes
2012-01-06 08:02:18.619 ThemeCatcher[2667:207] CoreData: error: Failed to call
designated initializer on NSManagedObject class 'Themes'
2012-01-06 08:02:19.000 ThemeCatcher[2667:207] -[Themes themeName]: unrecognized
selector sent to instance 0x87072d0
If anyone has any suggestion or ideas where I can go from here that would be awesome. I apologize if this seems like a lot of code to look at but I felt it was nessicarry to give others an idea what really is going on inside the code... Thank you I appreciate any help given immensely!
themesObjects = [[Themes alloc]init];
managedObjectContext = [[NSManagedObjectContext alloc] init];
I see two things wrong in these two lines. First, you're not using the designated initializer for NSManagedObject in your Themes initializer. I know that for two reasons: a) that's exactly what the error message says; b) the initializer can't know what context to use because you haven't created the context at that point. The designated initializer for NSManagedObjectContext is:
-initWithEntity:insertIntoManagedObjectContext:
However, it's common practice to use NSEntityDescription's + insertNewObjectForEntityForName:inManagedObjectContext: convenience method to create and add new objects to a context instead. Either way, you need to use one of these.
The second problem is that you don't have a managed object context when you create your Themes object, and it looks like you're not setting up the context correctly when you do create it. You should be setting a persistent store coordinator for the context after you create it.
Update: A third problem is that when you write:
themesObjects = (Themes *)[NSEntityDescription insertNewObjectForEntityForName:themesObjects.themeName" inManagedObjectContext:managedObjectContext];
you need to make sure that the model has an entity that matches the value of themeObjects.themeName. It'd be unusual to use data that you get from an XML file to determine the theme name, because a mistake in the XML file would cause an error, and also because it strongly ties the structure of the XML to your Core Data model. Be sure that you're not confusing the concept of XML entity with Core Data entity -- those are two different things. Core Data entities are the different types of objects in your model; you probably have an entity for Themes, for example.

Multiple NSXMLParser get "BAD ACCESS"

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.

NSXMLParser values not being retained

This is similar to my previous question. I didn't get an answer, maybe by changing the question I might get an answer.
Here is my parsing code:
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName
namespaceURI:(NSString *) namespaceURI
qualifiedName:(NSString *) qName
attributes:(NSDictionary *) attributeDict
{
if ([elementName isEqualToString:kimgurl]
|| [elementName isEqualToString:kone_x]
|| [elementName isEqualToString:kone_y]
|| [elementName isEqualToString:kone_radius]
|| [elementName isEqualToString:ktwo_x]
|| [elementName isEqualToString:ktwo_y]
|| [elementName isEqualToString:ktwo_radius])
{
elementFound = YES;
theItems = [[Items alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:kimgurl])
{
theItems.imageURL = self.currentValue;
[self.currentValue setString:#""];
}
else if([elementName isEqualToString:kone_x])
{
theItems.iOne_X = self.currentValue;
[self.currentValue setString:#""];
}
else if([elementName isEqualToString:kone_y])
{
theItems.iOne_Y = self.currentValue;
[self.currentValue setString:#""];
}
else if([elementName isEqualToString:kone_radius])
{
theItems.iOne_Radius = self.currentValue;
[self.currentValue setString:#""];
}
else if([elementName isEqualToString:ktwo_x])
{
theItems.iTwo_X = self.currentValue;
[self.currentValue setString:#""];
}
else if([elementName isEqualToString:ktwo_y])
{
theItems.iTwo_Y = self.currentValue;
[self.currentValue setString:#""];
}
else if([elementName isEqualToString:ktwo_radius])
{
theItems.iTwo_Radius = self.currentValue;
[self.currentValue setString:#""];
}
}
-(void) parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"enddocument: %#", theItems.imageURL);
}
-(void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string
{
if (elementFound == YES) {
if(!currentValue)
{
currentValue = [NSMutableString string];
}
[currentValue appendString: string];
}
}
When I get to parserDidEndDocument. The theItems class is empty.
Here is Items.h
#import <Foundation/Foundation.h>
#interface Items : NSObject {
#private
//parsed data
NSString *imageURL;
NSString *iOne_X;
NSString *iOne_Y;
NSString *iOne_Radius;
NSString *iTwo_X;
NSString *iTwo_Y;
NSString *iTwo_Radius;
}
#property (nonatomic, retain) NSString *imageURL;
#property (nonatomic, retain) NSString *iOne_X;
#property (nonatomic, retain) NSString *iOne_Y;
#property (nonatomic, retain) NSString *iOne_Radius;
#property (nonatomic, retain) NSString *iTwo_X;
#property (nonatomic, retain) NSString *iTwo_Y;
#property (nonatomic, retain) NSString *iTwo_Radius;
#end
here is Items.m
#import "Items.h"
#implementation Items
#synthesize imageURL;
#synthesize iOne_X;
#synthesize iOne_Y;
#synthesize iOne_Radius;
#synthesize iTwo_X;
#synthesize iTwo_Y;
#synthesize iTwo_Radius;
-(void)dealloc
{
[imageURL release];
[iOne_X release];
[iOne_Y release];
[iOne_Radius release];
[iTwo_X release];
[iTwo_Y release];
[iTwo_Radius release];
[super dealloc];
}
#end
here is my RootViewController.h
#import <UIKit/UIKit.h>
#class Items;
#interface RootViewController : UIViewController <NSXMLParserDelegate> {
NSMutableData *downloadData;
NSURLConnection *connection;
BOOL elementFound;
NSMutableString *currentValue;
NSMutableDictionary *pictures;
//---xml parsing---
NSXMLParser *xmlParser;
Items *theItems;
NSMutableArray *aItems;
}
#property (nonatomic, retain) Items *theItems;
#property (nonatomic, retain) NSMutableArray *aItems;
#property (nonatomic, retain) NSMutableString *currentValue;
#property (nonatomic, retain) NSMutableData *downloadData;
#property (nonatomic, retain) NSURLConnection *connection;
#end
xml file example
<?xml version="1.0" encoding="utf-8"?>
<data>
<test>
<url>url</url>
<one_x>83</one_x>
<one_y>187</one_y>
<one_radius>80</one_radius>
<two_x>183</two_x>
<two_y>193</two_y>
<two_radius>76</two_radius>
</test>
</data>
It looks like there are a couple of potential problems. In your didStartElement method you are alloc/init'ing a new Items object for every element and overwriting your previous one. Perhaps you can move the Items init into your –parserDidStartDocument: method. When you init, it should also look more like this:
Items *items = [[Items alloc] init];
self.theItems = items;
[items release];
Then you'll have the correct retain count when you are done.
I'd also recommend changing your NSString #property declarations to be copy instead of retain. The code:
theItems.imageURL = self.currentValue;
[self.currentValue setString:#""];
... isn't doing what you think. theItems.imageURL is going to be pointing at your NSMutableString and then you clear the mutable string right after which means imageURL is pointing at an empty mutable string. Then after all of the other iterations, all of them are pointing at the same NSMutableString which is empty. If you change the #property declarations to copy, then it'll set imageURL to an immutable NSString copy of the contents of self.currentValue.

iPhone: memory leak on autoreleased object?

I am using the XMLParser class, which contains an array with XMLElement objects. The XMLElement is being allocated using the autorelease operation. However, for some reason I'm getting a memory leak (using instruments) on this line:
self.currentElement = [[[XMLElement alloc] init] autorelease];
I'm also releasing the XMLParser object in the caller class. I've highlighted the "problematic" lines in the XMLParser source code below as comment.
I really tried everything to fix it, but unfortunately I do not understand why this is happening at all. Any help is appreciated!
Thank you very much!
// --- XMLElement
#import <Foundation/Foundation.h>
#interface XMLElement : NSObject {
NSDictionary *attributes;
NSMutableArray *children;
NSString *textValue;
NSString *tagName;
XMLElement *parentElement;
}
-(id) init;
-(void) addChild:(XMLElement*) child;
#property(nonatomic, retain) NSDictionary *attributes;
#property(nonatomic, retain) NSMutableArray *children;
#property(nonatomic, retain) NSString *textValue;
#property(nonatomic, retain) NSString *tagName;
#property(nonatomic, retain) XMLElement *parentElement;
#end
#import "XMLElement.h"
#implementation XMLElement
#synthesize attributes, children, textValue, parentElement, tagName;
-(id)init {
if(self = [super init]) {
children = [[NSMutableArray alloc] init];
}
return self;
}
-(void) addChild:(XMLElement*) child{
[self.children addObject:child];
}
- (void)dealloc {
[attributes release];
[children release];
[textValue release];
[tagName release];
[parentElement release];
[super dealloc];
}
#end
// --- XMLParser
#import <Foundation/Foundation.h>
#import "XMLElement.h"
#interface XMLParser : NSObject<NSXMLParserDelegate> {
XMLElement *currentElement;
XMLElement *currentParentElement;
NSMutableString *currentElementValue;
}
- (BOOL)parseData: (NSData*) dataToParse;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
#property (nonatomic, retain) XMLElement *currentParentElement;
#property (nonatomic, retain) XMLElement *currentElement;
#property (nonatomic, retain) NSMutableString *currentElementValue;
#end
#import "XMLParser.h"
#implementation XMLParser
#synthesize currentElementValue, currentElement, currentParentElement;
- (BOOL)parseData: (NSData*) dataToParse {
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:dataToParse];
[parser setDelegate:self];
BOOL success = [parser parse];
[parser release];
return success;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict{
if(currentElement){
self.currentParentElement = currentElement;
}
// ------------------------------------------------------------
// Instruments is marking this line as source of the leak with 90%
self.currentElement = [[[XMLElement alloc] init] autorelease];
// --------
currentElement.tagName = elementName;
currentElement.attributes = attributeDict;
currentElement.parentElement = self.currentParentElement;
if(self.currentParentElement){
[self.currentParentElement addChild:currentElement]; // and this one with 10%
}
self.currentElementValue = nil;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(!currentElement) {
return;
}
if(currentElementValue == nil)
self.currentElementValue = [NSMutableString stringWithString:string];
else
[currentElementValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if(currentElement == nil){
if( currentParentElement.parentElement){
self.currentParentElement = currentParentElement.parentElement;
}
}else{
currentElement.textValue = currentElementValue;
[currentElementValue release];
currentElementValue = nil;
self.currentParentElement = currentElement.parentElement;
currentElement = nil;
}
}
- (void)dealloc {
[currentParentElement release];
[currentElement release];
[super dealloc];
}
#end
You must release currentElement in your dealloc method in XMLParser.
It's created as autorelease but then assigned to a retain property, so you are actually retaining it once (which is good).
UPDATE: you should do self.currentElement = nil; when you are done with it, not currentElement = nil;.
This:
self.currentElement = [[[XMLElement alloc] init] autorelease];
retains currentElement (because the property is declared with retain).
Later, in parser:didEndElement:namespaceURI:qualifiedName:, you do this:
currentElement = nil;
which causes the leak because you are not releasing currentElement.
From what I see on this page, this is a documented apple bug. I have experienced the same problem in some of my apps...
Is your XMLParser being run on a background thread? If so, you need to create an NSAutoReleasePool for that thread in order for your [[[XMLElement alloc] init] autorelease] call to work.
HI guys.
the reason is just one simple thing,
instead of
#property(nonatomic, retain) XMLElement *parentElement;
must be
#property(nonatomic, assign) XMLElement *parentElement;
also you need delete [parentElement release] from dealloc
reason is that you are creating cyclic referances. parent to child and chils to parent
and when you are realesing parser object the elements still ocurrs in memory with pointer xount > 0