Using the copy attribute causes a segmentation fault - ios

I have started a Master Detail application and left the generated code untouched. I created and added two additional classes: a book class(contains an NSString for a title, author, and summary) and also a data controller class(contains a mutable array to store the books).
My understanding of #property attributes after reading Apple doc and others is this:
strong - default, creates ownership of an object
weak - alternative to strong, used to avoid retain cycles
copy - creates a copy of the existing object and takes ownership of that
nonatomic - disregards any sort of thread safety
This code throws a segmentation fault in addBookToList when the #property AJKBook is declared with the copy attribute and I don't understand why.
#interface AJKBookDataController ()
// when current book uses the copy attribute code seg faults in addBookToList
#property (nonatomic) AJKBook *currentBook;
#property (nonatomic, copy) NSString *currentValue;
- (void)populateBookList;
- (void)addBookToBookList;
#end
#implementation AJKBookDataController
- (id)init
{
self = [super init];
if (self) {
_bookList = [[NSMutableArray alloc] init];
_currentBook = [[AJKBook alloc] init];
_currentValue = [[NSString alloc] init];
[self populateBookList];
return self;
}
return nil;
}
- (void)setBookList:(NSMutableArray *)bookList
{
// this bit of code ensures bookList stays mutable
if (_bookList != bookList) {
_bookList = [bookList mutableCopy];
}
}
- (void)populateBookList
{
NSURL *url = [NSURL URLWithString:#"https://sites.google.com/site/iphonesdktutorials/xml/Books.xml"];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
NSLog(#"%#", [self.bookList description]);
}
- (void)addBookToBookList
{
[self.bookList addObject:self.currentBook];
self.currentBook = [[AJKBook alloc] init];
}
...
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"title"]) {
// [self.currentBook title:self.currentValue];
self.currentBook.title = self.currentValue;
} else if ([elementName isEqualToString:#"author"]) {
self.currentBook.author = self.currentValue;
} else if ([elementName isEqualToString:#"summary"]) {
self.currentBook.summary = self.currentValue;
} else if ([elementName isEqualToString:#"Book"]) {
[self addBookToBookList];
}
self.currentValue = [NSString stringWithFormat:#""];
}
#end

if you want to use copy for your custom classes you have to implement – copyWithZone: in those classes.
But you don't have to use copy. Often strong is good enough. copy is mostly used for NSString properties because you want to prevent that a NSMutableString is assigned and later changed from outside the class.
You have to think if you really need to copy the current book. If something is named current in my opinion that's a strong indication that you do NOT want to copy. If the only assignment is from [[AJKBook alloc] init]; copy does not make sense at all.

Related

XML Parsing goes to EXC_BAD_ACCESS code 1 address 0x10

So here is the thing. I am trying to build no-ARC/no-Storyboard project without previous experience in manual memory-management.
Full source code available here.
So what I've got here is a
class, which helps me create Products object with custom initialiser
Products.h
#interface Products : NSObject
#property (nonatomic,retain)NSString *productName;
#property (nonatomic,retain)NSString *productDescription;
#property (nonatomic,retain)NSString *productImage;
-(id) initWithName: (NSString *) name
description: (NSString *) description
image: (NSString *) image;
#end
Products.m
#implementation Products
-(id) initWithName:(NSString *)name description:(NSString *)description image:(NSString *)image {
self = [super init];
if (self) {
self.productName = name;
self.productDescription = description;
self.productImage = image;
}
return self;
#end
There you can see ProductParser class, which one contains most of magic
ProductsParser.h
#interface ProductsParser : NSObject <NSXMLParserDelegate>
#property (nonatomic,retain) NSMutableArray *productArray;
-(id) initWithArray:(NSMutableArray *) productArray;
-(void) parseXMLFile;
#end
ProductParser.m
// Creating private properties
#interface ProductsParser()
#property NSXMLParser *parser;
#property NSString *element;
#property NSMutableString *currentProductName;
#property NSMutableString *currentProductDescription;
#property NSMutableString *currentProductImage;
#end
#implementation ProductsParser
-(id) initWithArray:(NSMutableArray *)productArray {
self = [super init];
if (self) {
self.productArray = productArray;
}
return self;
}
-(void) parseXMLFile {
// We will do it here instead of writing that in viewDidLoad
NSURL *xmlPath = [[NSBundle mainBundle]URLForResource:#"productsList" withExtension:#"xml" ];
self.parser = [[NSXMLParser alloc]initWithContentsOfURL:xmlPath];
self.parser.delegate = self;
[self.parser parse];
[self.parser release];
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
self.element = elementName;
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
string = [string stringByReplacingOccurrencesOfString:#"\n" withString:#""];
string = [string stringByReplacingOccurrencesOfString:#"\t" withString:#""];
string = [string stringByReplacingOccurrencesOfString:#" " withString:#""];
if ([self.element isEqualToString:#"Name"]) {
if (self.currentProductName == nil) {
self.currentProductName = [[NSMutableString alloc] initWithString:string];
} else {
[self.currentProductName appendString:string];
}
}
if ([self.element isEqualToString:#"Description"]) {
if (self.currentProductDescription == nil) {
self.currentProductDescription = [[NSMutableString alloc] initWithString:string];
} else {
[self.currentProductDescription appendString:string];
}
} if ([self.element isEqualToString:#"Image"]) {
if (self.currentProductImage == nil) {
self.currentProductImage = [[NSMutableString alloc] initWithString:string];
} else {
[self.currentProductImage appendString:string];
}
}
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"Product"]) {
Products *thisProduct = [[Products alloc] initWithName:self.currentProductName description:self.currentProductDescription image:self.currentProductImage];
[self.productArray addObject:thisProduct];
[self.currentProductName release];
self.currentProductName = nil;
[self.currentProductDescription release];
self.currentProductDescription = nil;
[self.currentProductImage release];
self.currentProductImage = nil;
[thisProduct release];
thisProduct = nil;
[self.element release];
self.element = nil;
}
}
#end
Later on, in the class which is suppose to handle the UITableView I am creating:
#property (retain,nonatomic)NSMutableArray *productArray;
And In viewDidLoad we have this code
self.productArray = [[NSMutableArray alloc] init];
ProductsParser *menuParser = [[ProductsParser alloc] initWithArray:self.productArray];
[menuParser parseXMLFile];
[menuParser release];
All that results in EXC_BAD_ACCESS pointing to
#property (nonatomic,retain)NSString *productName;
I've done some research about that error. Users claims that they successfully getting rid of that error by simply calling properties with self. syntax.(which is suppose to increase retain count?) In my case it is not the issue, as you may see.(Or did I missed something?)
I am also can see in debugger that productArray which is suppose to be populated with my products from .xml file, is in fact populated by trash stuff like #"/n/t" #"/n " #"/n/t" and so on.(why why why?!)
So at least point it to me, where to start. Really appreciate your guys help.
UPDATE 1: Apparently there was some defect logic, I almost got rid of the \n\t stuff by changing code in foundCharacters section.
So now instead of just \n\t \n \n\t I got actual data in my array with those afterwards. Like so:
#"Box of chocolate \n\t\t"
#"Box of chocolate, very tasty \n"
#"ImageName \n\t"
I know that \n should be like new line, and \t is apparently tabulation. Still, don't have a clear idea on how to completely get rid of those and why are they popping up.
UPDATE 2: I manage to get rid of the trashy \n\t from the array by adding stringByReplacingOccurrencesOfString. (code updated)

Accessing arrays in another instance of a class objective c

I have a #property (nonatomic,retain) NSMutableArray *transfer_array; in .h file and in my .m I have
#synthesize transfer_array = _transfer_array;
- (id)init
{
self = [super init];
if(self) {
self.transfer_array = [[NSMutableArray alloc] init];
}
return self;
}
and I add objects to the array in this function
- (id)display:(double)imageXX andY:(double)imageYY withName:(NSString *)namee{
//if((self == [super init])){
NSLog(#"````````````````````````````````````````````````````````");
NSLog(#"imageX: %f",imageXX);
NSLog(#"imageY: %f", imageYY);
NSLog(#"name: %#", namee);
labelPoi = [[Poi alloc] init];
labelPoi.imageLocationX = imageXX;
labelPoi.imageLocationY = imageYY;
labelPoi.name = namee;
[self.transfer_array addObject:labelPoi];
The objects add successfully bu whenever I try to access the array elements in another instance such as:
- (void)viewDidLoad{
[super viewDidLoad];
NSLog(#"transfer_array count: %lu",(unsigned long)self.transfer_array.count);
Then the array is empty.
Any help would be appreciated!
Instances are independent objects. Changing the internal state of one doesn't affect the internal state of others.

NSXMLParser terminating due to NSUnknownKeyException

I am having trouble parsing an XML document to my project. I am getting the following error:
Terminating app due to uncaught exception 'NSUnknownKeyException',
reason: '[ setValue:forUndefinedKey:]: this class is
not key value coding-compliant for the key morph.'
Here is a snippet of my XML document:
<?xml version="1.0" encoding="utf-8"?>
<CAS version="2.1" avatar="anna">
<frames count="111" signCount="3">
<signStart index="0" gloss="mug" />
<frame index="0" isComplete="true" time="0" duration="20" boneCount="74"
morphCount="51">
<morph name="aaa" amount="0" />
<morph name="ooo" amount="0" />
<morph name="pout" amount="0" />
<morph name="eee" amount="0" />
<morph name="cgng" amount="0" />
Here is my code in my XMLParser.h file:
#import <Foundation/Foundation.h>
#class User;
#interface XMLParser : NSObject {
// an ad hoc string to hold element value
NSMutableString *currentElementValue;
// user object
User *user;
// array of user objects
NSMutableArray *times;
NSMutableArray *durations;
NSMutableArray *wheres;
}
#property (nonatomic, retain) User *user;
#property (nonatomic, retain) NSMutableArray *times;
#property (nonatomic, retain) NSMutableArray *durations;
#property (nonatomic, retain) NSMutableArray *wheres;
- (XMLParser *) initXMLParser;
#end
and XMLParser.m
#import "XMLParser.h"
#import "User.h"
#implementation XMLParser
#synthesize user, times, durations, wheres;
- (XMLParser *) initXMLParser {
self = [super init];
if(self){
// init array of user objects
times = [[NSMutableArray alloc] init];
durations = [[NSMutableArray alloc] init];
// wheres = [[NSMutableArray alloc] init];
}
return self;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if(![elementName isEqual:#"frame"])
return;
NSLog(#"user element found – create a new instance of User class...");
user = [[User alloc] init];
//We do not have any attributes in the user elements, but if
// you do, you can extract them here:
NSString *time = [attributeDict objectForKey:#"time"];
NSString *duration = [attributeDict objectForKey:#"duration"];
//NSString *where = [attributeDict objectForKey:#"where"];
[times addObject:time];
[durations addObject:duration];
// [wheres addObject:where];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentElementValue) {
// init the ad hoc string with the value
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
// append value to the ad hoc string
[currentElementValue appendString:string];
}
NSLog(#"Processing value for : %#", string);
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"CAS"]) {
// We reached the end of the XML document
NSLog(#"names array: %#", times);
NSLog(#"prices array: %#", durations);
// NSLog(#"wheres array: %#", wheres);
return;
}
if ([elementName isEqualToString:#"frame"]) {
// We are done with user entry – add the parsed user
// object to our user array
//[users addObject:user];
//user = nil;
} else {
// The parser hit one of the element values.
// This syntax is possible because User object
// property names match the XML user element names
[user setValue:currentElementValue forKey:elementName];
}
currentElementValue = nil;
}
I assume it has something to do with my xml file, but am not 100% on the exact problem.
Any help would be much appreciated.
Cheers,
Sam
Offhand it looks like your User object doesn't actually have a property called 'morph'. Double check that you spelled it properly, and it's actually the right class at runtime.
Does your user class implement KVO for the key "morph"?
What your User class needs to have to be considered KVC
Can you post the interface and implementation of your User class? That would be handy.
More about implementing KVO
I discovered the problem was due to this line of code:
[user setValue:currentElementValue forKey:elementName];
I have temporarily removed it from my code until I understand why it is make the program throw an exception

Class with memory leaks in instruments

I have a couple of classes which functions are execute SQL statements against a WEB service in order to get or set data in the database.
Works fine, but the problem is when I'm testing in instruments/leaks the 90% of the leaks are because these classes.
Could you tell me what I'm loosing?
Thanks.
Here is the code:
Where the data is stored:
.h
#interface iSQLResult : NSObject {
NSMutableArray *Records;
}
#property (nonatomic, assign) int CountX;
#property (nonatomic, assign) int CountY;
#property (nonatomic, retain) NSMutableArray *Columns;
#property (nonatomic, retain) NSMutableArray *Records;
#property (nonatomic, retain) NSMutableArray *FieldsNames;
#property (nonatomic, assign) int ErrorCode;
#property (nonatomic, retain) NSString *ErrorDescription;
-(void)addField:(NSString*)fieldName;
-(void)addRecord:(NSMutableArray*)items;
-(NSMutableArray *)getRecord:(int)y;
-(NSString*)getValue:(int) x posY:(int) y;
-(NSString*)getValueByName:(NSString *) colName posY:(int) y;
-(void)setValueByName:(NSString *) colName posY:(int) y value:(NSString *)value;
-(id) copyWithZone: (NSZone *) zone;
#end
.m
#import "iSQLResult.h"
#import <stdarg.h>
#implementation iSQLResult
#synthesize CountX;
#synthesize CountY;
#synthesize Columns;
#synthesize Records;
#synthesize FieldsNames;
#synthesize ErrorCode;
#synthesize ErrorDescription;
-(id)init
{
self = [super init];
if (self)
{
self.CountX =0;
self.CountY =0;
self.ErrorCode = 0;
self.ErrorDescription = #"";
self.FieldsNames = [NSMutableArray array];
self.Columns = [NSMutableArray array];
self.Records = [NSMutableArray array];
}
return self;
}
-(void)removeRecord:(int)index
{
[self.Records removeObjectAtIndex:index];
self.CountY = self.CountY - 1;
}
-(void)addField:(NSString*)fieldName
{
[self.FieldsNames addObject:[NSString stringWithFormat:#"%#", fieldName]];
self.CountX = self.CountX +1;
}
-(void)addRecord:(NSMutableArray*)items
{
[self.Records addObject:items];
self.CountY = self.CountY +1;
}
-(NSMutableArray *)getRecord:(int)y
{
return [Records objectAtIndex:y];
}
-(NSString *)getValue:(int) x posY:(int)y
{
return [[NSString stringWithFormat:#"%#", [[Records objectAtIndex:y] objectAtIndex:x]] copy];
}
-(NSString*)getValueByName:(NSString *) colName posY:(int) y
{
int a=0;
for (a=0;a<CountX;a++)
{
if ([[colName uppercaseString] isEqualToString:[[FieldsNames objectAtIndex:a] uppercaseString]])
{
return [[NSString stringWithFormat:#"%#", [[Records objectAtIndex:y] objectAtIndex:a]] copy];
}
}
return #"";
}
-(void)setValueByName:(NSString *) colName posY:(int) y value:(NSString *)value
{
int a=0;
for (a=0;a<CountX;a++)
{
if ([[colName uppercaseString] isEqualToString:[[FieldsNames objectAtIndex:a] uppercaseString]])
{
[[Records objectAtIndex:y] replaceObjectAtIndex:a withObject:value];
}
}
}
-(void)dealloc
{
[Columns release];
[Records release];
[FieldsNames release];
[ErrorDescription release];
[super dealloc];
}
-(id) copyWithZone: (NSZone *) zone
{
iSQLResult *SQLRCopy = [[iSQLResult allocWithZone: zone] init];
[SQLRCopy setCountX:self.CountX];
[SQLRCopy setCountY:self.CountY];
[SQLRCopy setRecords:[self.Records mutableCopyWithZone:zone]];
[SQLRCopy setColumns:[self.Columns mutableCopyWithZone:zone]];
[SQLRCopy setFieldsNames:[self.FieldsNames mutableCopyWithZone:zone]];
[SQLRCopy setErrorCode:self.ErrorCode];
[SQLRCopy setErrorDescription:[self.ErrorDescription copyWithZone:zone]];
return SQLRCopy;
}
#end
The class who ask for the data to the web service comunication class and gets a xml structure:
.h
#import <Foundation/Foundation.h>
#import "iSQLResult.h"
#import "IM2_WebServiceComm.h"
#interface iSQL : NSObject <NSXMLParserDelegate> {
iSQLResult *SQLR;
IM2_WebServiceComm * WSC;
NSXMLParser *xmlParser;
BOOL Found;
BOOL FieldsReaded;
BOOL loadFieldsNow;
BOOL loadErrNumNow;
BOOL loadErrDesNow;
NSString *chunksString;
NSMutableArray *tempRecord;
}
#property (nonatomic, retain) NSString *URLConnection;
-(void)SQLReader:(NSString*)SQLString;
-(void)SQLExec:(NSString*)SQLString;
-(void)setURLConnection:(NSString *) WebSURL;
-(iSQLResult*) getSQLR;
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
-(void) parser:(NSXMLParser *) parser foundCharacters:(NSString *)string;
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *) attributeDict;
#end
.m
#import "iSQL.h"
#implementation iSQL
#synthesize URLConnection;
- (iSQLResult*)getSQLR
{
return [SQLR copy];
}
-(void)SQLExec:(NSString*)SQLString
{
FieldsReaded = NO;
Found = NO;
loadFieldsNow = NO;
if (SQLR)
{
[SQLR release];
SQLR = nil;
}
SQLR = [[iSQLResult alloc] init];
WSC = [[IM2_WebServiceComm alloc] init];
[WSC setURL:URLConnection];
NSString *theXML = [WSC callMethod:#"ExecNonQuery" sendInstruction:SQLString];
#try
{
xmlParser = [[NSXMLParser alloc] initWithData:[theXML dataUsingEncoding:NSUTF8StringEncoding]];
[xmlParser setDelegate: self];
[xmlParser setShouldResolveExternalEntities:NO];
if(![xmlParser parse])
{
NSLog(#"ERROR PARSING");
}
[xmlParser release];
}
#catch(NSException * ex)
{
NSLog(#"%#",[[ex reason] UTF8String]);
}
[WSC release];
}
-(void)SQLReader:(NSString*)SQLString
{
FieldsReaded = NO;
Found = NO;
loadFieldsNow = NO;
if (SQLR)
{
[SQLR release];
SQLR = nil;
}
SQLR = [[iSQLResult alloc] init];
WSC = [[IM2_WebServiceComm alloc] init];
[WSC setURL:URLConnection];
NSString *theXML = [WSC callMethod:#"ExecSQL" sendInstruction:SQLString];
#try
{
xmlParser = [[NSXMLParser alloc] initWithData:[theXML dataUsingEncoding:NSUTF8StringEncoding]];
[xmlParser setDelegate: self];
[xmlParser setShouldResolveExternalEntities:NO];
if(![xmlParser parse])
{
NSLog(#"ERROR PARSING");
}
[xmlParser release];
}
#catch(NSException * ex)
{
NSLog([NSString stringWithFormat:#"%#",[[ex reason] UTF8String]]);
}
[WSC release];
}
-(iSQLResult *)getSingleSQLR:(iSQLResult *)SQLSource usingRow:(int)y
{
iSQLResult *SQLRAux = [[[iSQLResult alloc]init]retain];
[SQLRAux setCountX:SQLSource.CountX];
[SQLRAux addRecord:[SQLSource getRecord:y]];
[SQLRAux setFieldsNames:SQLSource.FieldsNames];
return SQLRAux;
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSLog(#"Error on XML Parse: %#", [parseError localizedDescription] );
}
//#pragma XML Parser Delegate Methods
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *) attributeDict
{
if (!chunksString)
{
chunksString = [[NSString alloc] init];
}
chunksString = #"";
if ([elementName isEqualToString:#"ErrCode"])
{
loadErrNumNow = YES;
}
if ([elementName isEqualToString:#"ErrDesc"])
{
loadErrDesNow = YES;
}
if ([elementName isEqualToString:#"Table"])
{
Found = YES;
loadFieldsNow = NO;
tempRecord = [[NSMutableArray alloc] init];
}
if (Found && ![elementName isEqualToString:#"Table"])
{
loadFieldsNow = YES;
if (!FieldsReaded)
{
[SQLR addField:elementName];
}
}
}
-(void) parser:(NSXMLParser *) parser foundCharacters:(NSString *)string
{
chunksString = [chunksString stringByAppendingString:string];
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSString * finalString;
finalString = [NSString stringWithFormat:#"%#",chunksString];
if (loadErrNumNow)
{
[SQLR setErrorCode:[finalString intValue] ];
loadErrNumNow = NO;
}
if (loadErrDesNow)
{
[SQLR setErrorDescription:finalString];
loadErrDesNow = NO;
}
if (Found)
{
if (loadFieldsNow)
{
[tempRecord addObject:finalString];
}
}
if ([elementName isEqualToString:#"Table"])
{
[SQLR addRecord:tempRecord];
[tempRecord release];
Found = NO;
FieldsReaded = YES;
loadFieldsNow = NO;
}
}
-(void)dealloc
{
if (SQLR)
{
[SQLR release];
SQLR = nil;
}
[URLConnection release];
[super dealloc];
}
#end
This is an absolutely buggy class because the leaks, every access is a leak :(
Any help please?
Here are some things I notice:
-[iSQLResult copyWithZone:]
You're sending the result of mutableCopyWithZone: (which returns a retained object) to the setters, which retain the object again. One way to fix it is to autorelease the copy:
[SQLRCopy setRecords:[[self.Records mutableCopyWithZone:zone] autorelease]]
-[iSQL SQLExec:] and -[iSQL SQLReader:]
The ivars WSC and xmlPareser are alloced then released but not set to nil. This isn't a leak, but you're keeping a reference to a released object. If you dereference that, you'll crash.
-[iSQL getSingleSQLR:usingRow:]
iSQLResult *SQLRAux = [[[iSQLResult alloc]init]retain];
Did you mean autorelease instead of retain there? (And if you did, shouldn't you also autorelease the return in getSQLR, for consistency?)
-[iSQL parser:didStartElement:namespaceURI:qualifiedName:attributes:]
chunksString is alloced (+1 retain), but later in parser:foundCharacters: you're losing the reference (i.e., leaking the string) and replacing it with an autoreleased string.
That's all I notice off hand. It sounds like you're leaking more than just those objects, so I'm guessing you're leaking iSQL and/or iSQLResult objects, too. Remember, when you leak an object, you also leak everything those objects hold a reference to. Even if these classes were leak-free, if the code that's instantiating the classes isn't properly releasing the objects you'll see all the members in these classes leak, too. When fixing leaks, always look for "top-level" objects first.

NSXMLParserDelegate memory issues

I'm running my app through Instruments, and every time the following setup causes a memory leak (apparently). I can't see an issue with this.
WeatherParser.h:
...
{
NSMutableDictionary *results;
}
#property (nonatomic, retain) NSMutableDictionary *results;
WeatherParser.m
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
self.results = [[NSMutableDictionary alloc] init];
}
...add values to results
- (void)dealloc
{
self.results = nil;
[self.results release];
[super dealloc];
}
Would greatly appreciate any observations.
Swap these around to read:
[self.results release];
self.results = nil;
you were calling the release on the nil object not on the results array.

Resources