I am build an iPhone application who try to perform a login via a Rest web service (WCF).
The part who call the service work correctly. I receive data from the called service without any problem.
But I have to parse the message using the NSXMLParser. When I introduce it in my application (this is the first time I used it) the application parse the message correctly but at the end of the application execution it's lunch gdb and pause the application at the start of [pool drain] instruction.
#interface MessageParser : NSObject <NSXMLParserDelegate> {
NSMutableString* currentProperty;
Message* message;
}
#property (nonatomic, retain) NSMutableString* currentProperty;
#property (nonatomic, retain) Message* message;
- (void)parseMessageData:(NSData *)data parseError:(NSError **)err;
#end
#implementation MessageParser
#synthesize message, currentProperty;
- (void)parseMessageData:(NSData *)data parseError:(NSError **)err {
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
if (err && [parser parserError]) {
*err = [parser parserError];
}
[parser release];
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if(qName){
elementName = qName;
}
if([elementName isEqualToString:#"Message"]){
self.message = [[Message alloc] init];
}
else if( [elementName isEqualToString:#"body"] || [elementName isEqualToString:#"code"] || [elementName isEqualToString:#"error"]){
currentProperty = [NSMutableString string];
}
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if(qName){
elementName = qName;
}
if(message){
if([elementName isEqualToString:#"body"]){
self.message.messageBody = currentProperty;
}
else if([elementName isEqualToString:#"error"]){
self.message.error = currentProperty;
}
else if([elementName isEqualToString:#"code"]){
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
self.message.messageCode = [f numberFromString:currentProperty];
[f release];
}
}
self.currentProperty = nil;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)foundedCharacters
{
if (self.currentProperty) {
[currentProperty appendFormat:#"%#", foundedCharacters];
}
}
Some time the debugger give me this message : Attempting to create USE_BLOCK_IN_FRAME variable with block that isn't in the frame.
Do you have any idea ?
Thank you.
This can be done using method swizzling:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface NSAutoreleasePool(customDrain)
-(void) myDrain;
#end
#implementation NSAutoreleasePool(customDrain)
-(void) myDrain
{
if ([self respondsToSelector:#selector(myDrain)])
{
NSLog(#"Draining...");
// note that #selector(myDrain) was remapped
// to #selector(drain) during the process of
// the swizzling, so now, myDrain calls drain,
// and drain calls myDrain.
[self myDrain];
}
else
{
NSLog(#"Remapping Failed!");
}
}
#end
void SwizzleMethod(Class c, SEL orig, SEL new);
void SwizzleMethod(Class c, SEL orig, SEL new) {
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if (origMethod && newMethod)
method_exchangeImplementations(origMethod, newMethod);
}
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
SwizzleMethod([NSAutoreleasePool class], #selector(drain), #selector(myDrain));
[pool drain];
return 0;
}
You simply put your own code in the category's myDrain method, and, then, you run your own code when the pool is drained.
I hope this helped.
Related
I am currently having a problem with parsing information from an XML into an NSMutableArray, i have pasted the code below which is for the parser this retrieves the document off the internet and constructs the array. I am then trying to copy the items from the xml parser into an NSMutableArray for searching, but every time i try to copy the array it returns a struct error so i have removed the changes for now.
Here is the code for the parser and the current code for the viewdidload in the main view controller, if anyone can help i would really appreciate it.
#import "BlogRssParser.h"
#import "BlogRss.h"
#implementation BlogRssParser
#synthesize currentItem = _currentItem;
#synthesize currentItemValue = _currentItemValue;
#synthesize rssItems = _rssItems;
#synthesize delegate = _delegate;
#synthesize retrieverQueue = _retrieverQueue;
- (id)init{
if(![super init]){
return nil;
}
_rssItems = [[NSMutableArray alloc]init];
return self;
}
- (NSOperationQueue *)retrieverQueue {
if(nil == _retrieverQueue) {
_retrieverQueue = [[NSOperationQueue alloc] init];
_retrieverQueue.maxConcurrentOperationCount = 1;
}
return _retrieverQueue;
}
- (void)startProcess{
SEL method = #selector(fetchAndParseRss);
[[self rssItems] removeAllObjects];
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self
selector:method
object:nil];
[self.retrieverQueue addOperation:op];
[op release];
}
-(BOOL)fetchAndParseRss{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//To suppress the leak in NSXMLParser
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSURL *url = [NSURL URLWithString:#"http://xxxxxxxxx.co.uk/rssparser/Data.xml"];
BOOL success = NO;
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:YES];
[parser setShouldReportNamespacePrefixes:YES];
[parser setShouldResolveExternalEntities:NO];
success = [parser parse];
[parser release];
[pool drain];
return success;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict{
if(nil != qualifiedName){
elementName = qualifiedName;
}
if ([elementName isEqualToString:#"item"]) {
self.currentItem = [[[BlogRss alloc]init]autorelease];
} else if([elementName isEqualToString:#"title"] ||
[elementName isEqualToString:#"description"] ||
[elementName isEqualToString:#"mediaUrl"] ||
[elementName isEqualToString:#"link"] ||
[elementName isEqualToString:#"guid"] ||
[elementName isEqualToString:#"pubDate"]) {
self.currentItemValue = [NSMutableString string];
} else {
self.currentItemValue = nil;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if(nil != qName){
elementName = qName;
}
if([elementName isEqualToString:#"title"]){
self.currentItem.title = self.currentItemValue;
}else if([elementName isEqualToString:#"description"]){
self.currentItem.description = self.currentItemValue;
}else if([elementName isEqualToString:#"link"]){
self.currentItem.linkUrl = self.currentItemValue;
}else if([elementName isEqualToString:#"mediaUrl"]){
self.currentItem.mediaUrl = self.currentItemValue;
}else if([elementName isEqualToString:#"guid"]){
self.currentItem.guidUrl = self.currentItemValue;
}else if([elementName isEqualToString:#"pubDate"]){
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss'Z'"];
self.currentItem.pubDate = [formatter dateFromString:self.currentItemValue];
[formatter release];
}else if([elementName isEqualToString:#"item"]){
[[self rssItems] addObject:self.currentItem];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(nil != self.currentItemValue){
[self.currentItemValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock{
//Not needed for now
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
if(parseError.code != NSXMLParserDelegateAbortedParseError) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[(id)[self delegate] performSelectorOnMainThread:#selector(processHasErrors)
withObject:nil
waitUntilDone:NO];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[(id)[self delegate] performSelectorOnMainThread:#selector(processCompleted)
withObject:nil
waitUntilDone:NO];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
-(void)dealloc{
self.currentItem = nil;
self.currentItemValue = nil;
self.delegate = nil;
[_rssItems release];
[super dealloc];
}
#end
BlogRSSParser.h
#import <Foundation/Foundation.h>
#class BlogRss;
#protocol BlogRssParserDelegate;
#interface BlogRssParser : NSObject <NSXMLParserDelegate>{
BlogRss * _currentItem;
NSMutableString * _currentItemValue;
NSMutableArray * _rssItems;
id<BlogRssParserDelegate> _delegate;
NSOperationQueue *_retrieverQueue;
}
#property(nonatomic, retain) BlogRss * currentItem;
#property(nonatomic, retain) NSMutableString * currentItemValue;
#property(readonly) NSMutableArray * rssItems;
#property(nonatomic, assign) id<BlogRssParserDelegate> delegate;
#property(nonatomic, retain) NSOperationQueue *retrieverQueue;
- (void)startProcess;
#end
#protocol BlogRssParserDelegate <NSObject>
-(void)processCompleted;
-(void)processHasErrors;
#end
ViewDidLoad
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
[self toolbarInit];
_rssParser = [[BlogRssParser alloc]init];
self.rssParser.delegate = self;
[[self rssParser]startProcess];
}
You rssItems array is marked "readonly".
Change:
#property(readonly) NSMutableArray * rssItems;
to
#property(nonatomic, retain) NSMutableArray * rssItems;
I previously asked this question XMLParser Advice.
However I am still unable to get it to function properly....
So I guess I will start from scratch:
Located at a certain URL is an XML Tree that looks like this
<result>
//stuff that I dont need
<title>
//thing that I do need
</title>
//stuff that I dont need
<body>
//thing that I do need
</body>
<result>
How the heck do I go about parsing that?
The (useless) code I have so far can be found in the link at the top of this question.
Thank you for your time.
Write a simple class, which will be the parser's delegate.
#interface YourObject : NSObject <NSXMLParserDelegate> {
NSString *title, *body; // object attributes
NSXMLParser *parser; // will parse XML
NSMutableString *strData; // will contains string data being parsed
}
#property(readwrite, copy) NSString *title, body;
// will be used to set your object attributes
-(void)fetchValuesAtURL:(NSString *)url;
#end
The fetchValuesAtURL: method will initiate the parse operation.
#implementation YourObject
#synthesize title, body;
-(id)init {
self = [super init];
if(self) {
title = #"";
body = #"";
parser = nil;
strData = [[NSMutableString alloc] initWithCapacity:10];
}
return self;
}
-(void)fetchValuesAtURL:(NSString *)url {
if(parser) {
[parser release];
}
NSURL *xmlURL = [NSURL URLWithString:url];
parser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[parser setDelegate:self];
[parser parse];
}
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
// element is about to be parsed, clean the mutable string
[strData setString:#""];
}
// the probably missing method
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// content (or part of) has been found, append that to the current string
[strData appendString:string];
}
-(void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
// element has been parsed, test the element name
// and store strData accordingly
if([elementName isEqualToString:#"title"]) {
self.title = strData;
}
else { // or else if, here you got two elements to parse
self.body = strData;
}
}
-(void)dealloc {
[title release];
[body release];
[strData release];
if(parser) {
[parser release];
}
[super dealloc];
}
#end
Then :
YourObject *obj = [[YourObject alloc] init];
[obj fetchValuesAtURL:#"http://www.site.com/xml/url"];
NSXMLParser's delegate is able to do many more things, as described in Event-Driven XML Programming Guide from Apple.
For complete reference on delegate methods, see NSXMLParserDelegate Protocol Reference.
I'm not sure what I am doing wrong. I have a URL leading to an XML tree that looks like:
<result>
...
<title>
...
</title>
<body>
...
</body>
...
</result>
I just need to parse the file and get the title and body. Here is my object.h:
#import <Foundation/Foundation.h>
#interface Object : NSObject
{
NSString *title;
NSString *description;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *description;
#end
And here is Object.m:
#import "Object.h"
#implementation Object
#synthesize title, description;
-(void) dealloc
{
[title release];
[description release];
[super dealloc];
}
#end
Here is my XMLParser.h:
#import <Foundation/Foundation.h>
#import "Object.h"
#interface XMLParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentNodeContent;
NSMutableArray *arrayOfObjects;
NSXMLParser *parser;
Object *currentObject;
}
#property (readonly, retain) NSMutableArray *arrayOfObjects;
-(id) loadXMLbyURL:(NSString *)urlString;
#end
And finally, XMLParser.m:
#import "XMLParser.h"
#import "Object.h"
#implementation XMLParser
#synthesize arrayOfObjects;
-(id) loadXMLbyURL:(NSString *)urlString
{
arrayOfObjects = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
-(void) dealloc
{
[parser release];
[super dealloc];
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"result"])
{
currentObject = [Object alloc];
}
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"title"])
{
currentObject.title = currentNodeContent;
}
if([elementName isEqualToString:#"body"])
{
currentObject.description = currentNodeContent;
}
if([elementName isEqualToString:#"result"])
{
[arrayOfObjects addObject:currentObject];
[currentObject release];
currentObject = nil;
[currentNodeContent release];
currentNodeContent = nil;
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
#end
In my main code I make a call to XML parser like this:
xmlParser = [[XMLParser alloc] loadXMLbyURL:#"www.websiteWithXML.com"];
However nothing is being placed into my arrayOfObjects (I know this because when I tell a tableview to have as many rows as my array, there are no rows).
please help!!! Thank you in advance!
Not sure if this will help...
Try changing:
arrayOfObjects = [[NSMutableArray alloc] init];
To:
arrayOfObjects = [[NSMutableArray alloc] initWithCapacity:0];
Other than that it appears that your code is fine. Also just because your table isn't loading anything doesn't mean that you do not have objects in your array. Use breakpoints to take a look at your data after you finish parsing and before you try to load your tableview.
Try resetting currentNodeContent inside each of your element starts. For example:
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"result"])
{
currentObject = [Object alloc];
}
else if ([elementName isEqualToString:#"title"] || [elementName isEqualToString:#"body"])
{
[currentNodeContent setString:#""];
}
}
Then, when you receive characters do an append:
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[currentNodeContent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
By doing this, you handle the situation where a foundCharacters gets multiple times to capture all of the characters within a given element.
I have an xml file I am parsing.
NSURL *url = [NSURL URLWithString:#"url.xml"];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
self.downloadData = [[NSMutableData alloc] initWithLength:0];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
I have all the connections working and I thought I had the parsing working but I am having issues and do not know what I am doing wrong.
my didStartElement:
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *) attributeDict {
if ([elementName isEqualToString:kimgurl])
{
elementFound = YES;
}
}
foundCharacter:
-(void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string {
if (elementFound == YES) {
if(!currentValue)
{
currentValue = [[NSMutableString alloc] init];
}
[currentValue appendString: string];
}
}
then didEndElement:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (elementFound) {
if ([elementName isEqualToString:kimgurl]) {
NSLog(#"imgurl: %#", currentValue);
imageItems.imageURL = currentValue;
NSLog(#"elname: %#", elementName);
NSLog(#"img: %#", kimgurl);
[currentValue setString:#""];
NSLog(#"imageitem: %#", imageItems.imageURL);
}
}
}
I have the NSLogs there because imageItems.imageURL is null. This is a class file that is like this.
ImageItems.h
#interface ImageItems : NSObject {
//parsed data
NSString *imageURL;
}
#property (nonatomic, retain) NSString *imageURL;
#end
ImageItems.m
#import "ImageItems.h"
#implementation ImageItems
#synthesize imageURL;
-(void)dealloc
{
[imageURL release];
[super dealloc];
}
#end
As you can tell by my code I am new to objective-c.
currentValue has the value Im looking for. Why is imageItems null? What am I missing?
I don't see the assignment of "imageItems" anywhere in your code. You probably need to assign it to an instance of ImageItems at some point. Perhaps with self.imageItems = [[[ImageItems alloc] init] autorelease] or imageItems = [[ImageItems alloc] init];?
I am building an app that parses an rss feed. In the app there are two different types of feeds with different names for the elements in the feed, so I have created an NSXMLParser NSObject that takes the name of the elements of each feed before parsing. Here is my code:
NewsFeedParser.h
#import
#interface NewsFeedParser : NSObject {
NSInteger NewsSelectedCategory;
NSXMLParser *NSXMLNewsParser;
NSMutableArray *newsCategories;
NSMutableDictionary *NewsItem;
NSMutableString *NewsCurrentElement, *NewsCurrentElement1, *NewsCurrentElement2, *NewsCurrentElement3;
NSString *NewsItemType, *NewsElement1, *NewsElement2, *NewsElement3;
NSInteger NewsNumElements;
}
- (void) parseXMLFileAtURL:(NSString *)URL;
#property(nonatomic, retain) NSString *NewsItemType;
#property(nonatomic, retain) NSString *NewsElement1;
#property(nonatomic, retain) NSString *NewsElement2;
#property(nonatomic, retain) NSString *NewsElement3;
#property(nonatomic, retain) NSMutableArray *newsCategories;
#property(assign, nonatomic) NSInteger NewsNumElements;
#end
NewsFeedParser.m
#import "NewsFeedParser.h"
#implementation NewsFeedParser
#synthesize NewsItemType;
#synthesize NewsElement1;
#synthesize NewsElement2;
#synthesize NewsElement3;
#synthesize newsCategories;
#synthesize NewsNumElements;
- (void)parserDidStartDocument:(NSXMLParser *)parser{
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
newsCategories = [[NSMutableArray alloc] init];
URL = [URL stringByReplacingOccurrencesOfString:#" " withString:#""];
URL = [URL stringByReplacingOccurrencesOfString:#"\n" withString:#""];
URL = [URL stringByReplacingOccurrencesOfString:#" " withString:#""];
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSXMLNewsParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[NSXMLNewsParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[NSXMLNewsParser setShouldProcessNamespaces:NO];
[NSXMLNewsParser setShouldReportNamespacePrefixes:NO];
[NSXMLNewsParser setShouldResolveExternalEntities:NO];
[NSXMLNewsParser parse];
[NSXMLNewsParser release];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to download story feed from web site (Error code %i )", [parseError code]];
NSLog(#"error parsing XML: %#", errorString);
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
[errorString release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NewsCurrentElement = [elementName copy];
if ([elementName isEqualToString:NewsItemType])
{
// clear out our story item caches...
NewsItem = [[NSMutableDictionary alloc] init];
NewsCurrentElement1 = [[NSMutableString alloc] init];
NewsCurrentElement2 = [[NSMutableString alloc] init];
if(NewsNumElements == 3)
{
NewsCurrentElement3 = [[NSMutableString alloc] init];
}
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:NewsItemType])
{
// save values to an item, then store that item into the array...
[NewsItem setObject:NewsCurrentElement1 forKey:NewsElement1];
[NewsItem setObject:NewsCurrentElement2 forKey:NewsElement2];
if(NewsNumElements == 3)
{
[NewsItem setObject:NewsCurrentElement3 forKey:NewsElement3];
}
[newsCategories addObject:[[NewsItem copy] autorelease]];
[NewsCurrentElement release];
[NewsCurrentElement1 release];
[NewsCurrentElement2 release];
if(NewsNumElements == 3)
{
[NewsCurrentElement3 release];
}
[NewsItem release];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
//NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([NewsCurrentElement isEqualToString:NewsElement1]) {
[NewsCurrentElement1 appendString:string];
} else if ([NewsCurrentElement isEqualToString:NewsElement2]) {
[NewsCurrentElement2 appendString:string];
} else if (NewsNumElements == 3 && [NewsCurrentElement isEqualToString:NewsElement3])
{
[NewsCurrentElement3 appendString:string];
}
}
- (void)dealloc {
[super dealloc];
[newsCategories release];
[NewsItemType release];
[NewsElement1 release];
[NewsElement2 release];
[NewsElement3 release];
}
When I create an instance of the class I do like so:
NewsFeedParser *categoriesParser = [[NewsFeedParser alloc] init];
if(newsCat == 0)
{
categoriesParser.NewsItemType = #"article";
categoriesParser.NewsElement1 = #"category";
categoriesParser.NewsElement2 = #"catid";
}
else
{
categoriesParser.NewsItemType = #"article";
categoriesParser.NewsElement1 = #"category";
categoriesParser.NewsElement2 = #"feedUrl";
}
[categoriesParser parseXMLFileAtURL:feedUrl];
newsCategories = [[NSMutableArray alloc] initWithArray:categoriesParser.newsCategories copyItems:YES];
[self.tableView reloadData];
[categoriesParser release];
If I run the app with the leaks instrument, the leaks point to the [NSXMLNewsParser parse] call in the NewsFeedParser.m.
Here is a screen shot of the Leaks instrument with the NSCFStrings leaking:
http://img139.imageshack.us/img139/3997/leaks.png
For the life of me I can't figure out where these leaks are coming from. Any help would be greatly appreciated.
The leak occurred in the didStartElement method. I was copying elementName without releasing it.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NewsCurrentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:NewsItemType])
{
// clear out our story item caches...
NewsItem = [[NSMutableDictionary alloc] init];
NewsCurrentElement1 = [[NSMutableString alloc] init];
NewsCurrentElement2 = [[NSMutableString alloc] init];
if(NewsNumElements == 3)
{
NewsCurrentElement3 = [[NSMutableString alloc] init];
}
}
}
You might also want to release (if necessary) the allocated NSMutableString properties before allocating another NSMutableString into the property like so:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if (NewsCurrentElement) {
[NewsCurrentElement release], NewsCurrentElement = nil;
}
NewsCurrentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:NewsItemType]) {
// clear out our story item caches...
if (NewsItem) {
[NewsItem release], NewsItem = nil;
}
NewsItem = [[NSMutableDictionary alloc] init];
if (NewsCurrentElement1) {
[NewsCurrentElement1 release], NewsCurrentElement1 = nil;
}
NewsCurrentElement1 = [[NSMutableString alloc] init];
if (NewsCurrentElement2) {
[NewsCurrentElement2 release], NewsCurrentElement2 = nil;
}
NewsCurrentElement2 = [[NSMutableString alloc] init];
if(NewsNumElements == 3) {
if (NewsCurrentElement3) {
[NewsCurrentElement3 release], NewsCurrentElement3 = nil;
}
NewsCurrentElement3 = [[NSMutableString alloc] init];
}
}
}