memory leak and instance variables - objective-c

-(void) getAccounts {
self.selAccounts = [[NSMutableArray alloc] init];
self.accounts = [[NSMutableArray alloc] init];
NSString *url=[NSString stringWithFormat:#"https://localhost//listaccts"];
self.processor=[[AsynConnectionProcessorController alloc] init];
self.processor.delegate=self;
self.processor.server=self.server;
[processor createRequestfromURL:url];
}
This method is causing memory leak when invoked. Now if I replace this with below
-(void) getAccounts {
[accounts release];
self.selAccounts = [[NSMutableArray alloc] init];
accounts = [[NSMutableArray alloc] init];
NSString *url=[NSString stringWithFormat:#"https://localhost//listaccts"];
self.processor=[[AsynConnectionProcessorController alloc] init];
self.processor.delegate=self;
self.processor.server=self.server;
[processor createRequestfromURL:url];
}
I am getting memory leak if I invoke this method second time as a result of viewcontroller beong popped from stack.
Why does this leak? accounts is an insyance variable with declration like this :
#property (nonatomic, retain) NSMutableArray *accounts;
Can't I assume that there won't be memory leak if I use setter via self.accounts?

This is wrong
self.accounts = [[NSMutableArray alloc] init];
the setter already does a retain, since you specified that in the property
#property (nonatomic, retain) NSMutableArray *accounts;
you should rewrite it like this
NSMutableArray arr = [[NSMutableArray alloc] init];
self.accounts = arr;
[arr release];
or alternatively:
self.accounts = [[[NSMutableArray alloc] init] autorelease];
EDIT: removed 'non preferred' - was subjective.

Related

memory menagement in ios

Can anybody explain me why does the case1 and case2 crashes while the others does not in case of non-ARC?
Case1:
NSString *rr = [[NSString alloc] initWithString:#"AB"];
[rr release];
[rr autorelease];
Case2:
NSString *rrr = [[NSString alloc] initWithString:#"AB"];
[rrr autorelease];
[rrr release];
Case3:
NSMutableString *rr1 = [[NSMutableString alloc] initWithString:#"AB"];
[rr1 release];
[rr1 autorelease];
Case4:
NSMutableString *rrr1 = [[NSMutableString alloc] initWithString:#"AB"];
[rrr1 autorelease];
[rrr1 release];
Case5:
NSArray *rr3 = [[NSArray alloc] initWithObjects:#"jj", nil];
[rr3 release];
[rr3 autorelease];
Case6:
NSArray *rrr3 = [[NSArray alloc] initWithObjects:#"jj", nil];
[rrr3 autorelease];
[rrr3 release];
Case7:
NSMutableArray *rr2 = [[NSMutableArray alloc] initWithObjects:#"jj", nil];
[rr2 release];
[rr2 autorelease];
Case8:
NSMutableArray *rr2 = [[NSMutableArray alloc] initWithObjects:#"jj", nil];
[rr2 autorelease];
[rr2 release];
All are are incorrect because eventually all will be released twice, but some may coincidentally not crash.
The alloc allocates the object with a retain count of 1. release decreases the retain count 1. autorelease eventually decreases the retain count 1. That means that all are over released.
But as #Chuck mentions some instances are constants, are created at compile time and never released so release and autorelease can be called to many tines with no crash.
String constants are one instance of this this where over-releasing will not cause a crash:
NSString *s = #"aa";
Even over-releasing this is OK because the compiler is smart enough:
NSString *s = [NSString stringWithString:#"aa"];
But you will get a warning from the current LLVM compiler that using stringWithString with a literal is redundant.

Can't add objects to a NSMutableArray

So I have the following code:
NSMutableArray *array
array=[[NSMutableArray alloc] init];
[array addObject: object1];
[array addObject: object2];
NSLog(#"%#",array);
When I use the app in my iPod connected to my Mac, NSLog writes just null, I don't get object1 object2. What am I doing wrong?
PS: array is a property in .h #property (nonatomic, retain) NSMutableArray *array;
Should it be:
array=[[NSMutableArray alloc] init];
Your [[NSMutableArray array] init] should be [[NSMutableArray alloc] init]. That would work but its not a proper way to initialize objects. You didn't post what your array is, i assume you declared it wrong. It should be a pointer to a NSMutableArray object. Here is a working code:
NSMutableArray *array=[[NSMutableArray alloc] init];
[array addObject: #"a"];
[array addObject: #"b"];
NSLog(#"%#",array);
You are not initializing your array at all, that's why it doesn't return anything.
array=[[NSMutableArray alloc] init];
[array addObject: object1];
[array addObject: object2];
NSLog(#" Array is:%#",array);
Remember to release it afterwards(unless you are using ARC)
You could try doing it in one line.
NSMutableArray *array = [[NSMutableArray alloc] arrayWithObjects:#"a", #"b", nil];
NSLog(#"%#",array);
You declared array as a property. Its corresponding iVar gets initialized to nil.
So in your init method you have to initialize it:
Assuming you used
#synthesize array;
In your init method
if (self) {
//other init stuff
array = [[NSMutableArray array] retain];
}
Then when adding stuff
[self.array addObject: object];
Also note that he objects you put in there have to be properly initialized and r not nil.
So try to log this too
NSLog("the object %# was put in array. Array contains: %#",object, self.array);
And in dealloc, release your array!

XML Parsing Class Leaking Strings on Rerun

I've been at this issue for two days, and no matter what I do, I cannot get it to stop leaking strings.
The class is a XML parser (using TouchXML), that is designed to run repeatedly throughout the life time of the application. The first time it runs, there are no leaks, everything cleans up perfectly. On the second run, it begins to leaks, almost always where ever strings are.
Some images from Instruments:
http://www.producerstudio.net/1.png
http://www.producerstudio.net/2.png
.h
#import <Foundation/Foundation.h>
#import "TouchXML.h"
#protocol RSSParsingComplete
-(void)parsingFinished;
#end
#interface RSS : NSObject<NSXMLParserDelegate>{
NSArray *rssURLArray;
NSMutableData *xmlData;
NSMutableArray *articles;
NSMutableArray *arrayOfArticles;
int numberOfFeeds;
NSDateFormatter *inputFormatter;
NSDateFormatter *outputFormatter;
id<RSSParsingComplete> delegate;
}
#property (nonatomic, retain) NSArray *rssURLArray;
#property (nonatomic, retain) NSMutableData *xmlData;
#property (nonatomic, retain) id<RSSParsingComplete> delegate;
#property (nonatomic, retain) NSMutableArray *articles;
#property (nonatomic, retain) NSMutableArray *arrayOfArticles;
#property (nonatomic, retain) NSDateFormatter *inputFormatter;
#property (nonatomic, retain) NSDateFormatter *outputFormatter;
-(id)initWithRSSArray:(NSArray *)inputURLArray;
-(void)connect;
-(NSArray *)feedArticles;
#end
.m
#import "RSS.h"
#implementation RSS
#synthesize xmlData, rssURLArray, articles, arrayOfArticles, delegate, inputFormatter, outputFormatter;
-(void)connect{
self.xmlData = [[[NSMutableData alloc] init] autorelease];
NSURL *rssURL = [[NSURL alloc] initWithString:[self.rssURLArray objectAtIndex:numberOfFeeds-1]];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:rssURL] delegate:self];
[urlConnection release];
[rssURL release];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[self.xmlData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.xmlData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
[xmlData release];
[connection release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
CXMLDocument *xmlDoc = [[[CXMLDocument alloc] initWithData:xmlData options:0 error:nil] autorelease];
self.articles = [[[NSMutableArray alloc] init] autorelease];
self.inputFormatter = [[[NSDateFormatter alloc] init] autorelease];
self.outputFormatter = [[[NSDateFormatter alloc] init] autorelease];
[self.inputFormatter setDateFormat:#"EEE, dd MMM yyyy HH:mm:ss zzz"];
[self.inputFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] autorelease]];
[self.inputFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
[self.outputFormatter setDateFormat:#"dd.MM.yyyy HH:mm:ss"];
[self.outputFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] autorelease]];
[self.outputFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSArray *itemNodes = [xmlDoc nodesForXPath:#"//item" error:nil];
for(CXMLElement *node in itemNodes){
NSMutableDictionary *article = [[NSMutableDictionary alloc] init];
for(int counter = 0; counter < [node childCount]; counter++){
if([[[node childAtIndex:counter] name] isEqualToString:#"title"]){
[article setObject:[[node childAtIndex:counter] stringValue] forKey:#"title"];
}
if([[[node childAtIndex:counter] name] isEqualToString:#"link"]){
[article setObject:[[node childAtIndex:counter] stringValue] forKey:#"url"];
}
if([[[node childAtIndex:counter] name] isEqualToString:#"description"]){
[article setObject:[[node childAtIndex:counter] stringValue] forKey:#"description"];
}
if([[[node childAtIndex:counter] name] isEqualToString:#"pubDate"]){
NSDate *tempDate = [self.inputFormatter dateFromString:[[node childAtIndex:counter] stringValue]];
[article setObject:[self.outputFormatter stringFromDate:tempDate] forKey:#"name"];
}
}
[self.articles addObject:article];
[article release];
}
NSArray *feedTitleNode = [xmlDoc nodesForXPath:#"//title" error:nil];
NSString *feedTitle = [[NSString alloc] initWithString:[[[feedTitleNode objectAtIndex:0] childAtIndex:0] stringValue]];
[self.articles addObject:feedTitle];
[feedTitle release];
[self.arrayOfArticles addObject:[articles copy]];
[self.articles removeAllObjects];
[inputFormatter release];
[outputFormatter release];
numberOfFeeds--;
if(numberOfFeeds > 0){
[self connect];
}else{
[delegate parsingFinished];
}
}
-(NSArray *)feedArticles{
NSLog(#"Array of Articles: %#", self.arrayOfArticles);
return self.arrayOfArticles;
}
-(id)initWithRSSArray:(NSArray *)inputURLArray{
self = [super init];
if (self) {
self.arrayOfArticles = [[[NSMutableArray alloc] init] autorelease];
self.rssURLArray = [[[NSArray alloc] initWithArray:inputURLArray] autorelease];
numberOfFeeds = [self.rssURLArray count];
[self connect];
}
return self;
}
-(void)dealloc{
[rssURLArray release];
[xmlData release];
[articles release];
[arrayOfArticles release];
[super dealloc];
}
- (id)init
{
self = [super init];
return self;
}
#end
I've done everything I can think of to resolve the leaks. I've read the Apple Memory Management guides, as well as the excellent guide on iPhoneDevSDK and that has helped me cut down on 90% of the leaks I originally had (the class doesn't leak so long as you call it once). Maybe i've been staring at this for too long, or maybe i'm missing something obvious.
I appreciate it!
First, should delegate be retained? I'm not sure why you need it as an instance variable at all. But since it's retained (and you don't seem to release it), your RSS object will retain a circular reference to itself and won't ever be released.
Second, do you need to keep the date formatters in an instance variable? It looks like you're allocating them and releasing them in the same method. Note that they're retained in the RSS instance and never released.

Memory Leak from NSMutableArray and NSDictionary

I have a memomry leak problem, maybe somebody can help me.
I try to load an NSMutable array for a pList and show some elements in a TablevView
In the h.File I declare
#interface Bestellung : UIViewController <UITableViewDelegate, UITableViewDelegate> {
NSMutableArray *bestellteVorspeisen;
NSMutableArray *bestellteVorspeisenPreis;
NSMutableArray *bestellteVorspeisenDetails;
NSMutableArray *bestellteVorspeisenBild;
NSMutableArray *bestellteVorspeisenNummer;
NSMutableArray *bestellListe;
IBOutlet UITableView *myTable;
}
#property (nonatomic, retain) NSMutableArray *bestellListe;
#property (nonatomic,retain) NSMutableArray *bestellteVorspeisen;
#property (nonatomic,retain) NSMutableArray *bestellteVorspeisenPreis;
#property (nonatomic,retain) NSMutableArray *bestellteVorspeisenDetails;
#property (nonatomic,retain) NSMutableArray *bestellteVorspeisenBild;
#property (nonatomic,retain) NSMutableArray *bestellteVorspeisenNummer;
#end
In the M.File viewDidLoad I load the pList in bestellListe
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Bestellung.plist"];
success = [fileManager fileExistsAtPath:filePath];
if (!success)
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"Bestellung" ofType:#"plist"];
success = [fileManager copyItemAtPath:path toPath:filePath error:&error];
}
self.bestellListe = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
Then I generate the MutableArray
bestellteVorspeisen = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenPreis = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenDetails = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenBild = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenNummer = [[NSMutableArray alloc] initWithCapacity:1];
Afterwards I fill them from bestellListe
for (NSDictionary *bestellDict in bestellListe)
{ if ([[bestellDict objectForKey:#"Tisch"] isEqualToString:
[NSString stringWithFormat:#"%i",TischNummer]])
{if ([[bestellDict objectForKey: kBestellungKategorieString] isEqualToString: #"Vorspeise"])
[bestellteVorspeisen addObject: [bestellDict objectForKey:kBestellungNameString]];
[bestellteVorspeisenPreis addObject: [bestellDict objectForKey:kBestellungPreisString]];
[bestellteVorspeisenDetails addObject: [bestellDict objectForKey:kBestellungDetailString]];
[bestellteVorspeisenBild addObject: [bestellDict objectForKey:kBestellungBildString]];
[bestellteVorspeisenNummer addObject: [bestellDict objectForKey:kBestellungNummer]];
} // if
} // if
} // for
This causes memoryleaks at
self.bestellListe = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
and
bestellteVorspeisen = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenPreis = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenDetails = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenBild = [[NSMutableArray alloc] initWithCapacity:1];
bestellteVorspeisenNummer = [[NSMutableArray alloc] initWithCapacity:1];
Here ist dealloc
- (void)dealloc {
NSLog(#"Bestellung dealloziert");
[bestellteVorspeisen release];
[bestellteVorspeisenPreis release];
[bestellteVorspeisenDetails release];
[bestellteVorspeisenBild release];
[bestellteVorspeisenNummer release];
[bestellListe release];
[myTable release];
[super dealloc];
Can somebody give me some help, I'm really new in that.
your property synthesized method automatically retains received objects :
#property (nonatomic, retain) NSMutableArray *bestellListe;
So when you do :
self.bestellListe = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
Your bestellListe has a retain count of 2 (the alloc + the retain from the property).
On your dealloc you only release it once :
[bestellListe release];
The simpler solution seems to retain it only once when creating it, with an autoreleased initializer like :
self.bestellListe = [NSMutableArray arrayWithContentsOfFile:filePath];
Hope this can help

Can I setup the tires array below as an NSArray?

I have looked on the web but can't find anything that might help. My question is can I write the tires[x] array as an NSArray, if so what would be the syntax to both declare and allocate the tire Class instance objects?
#interface CarClass : NSObject {
EngineClass *engine;
TireClass *tires[4];
}
.
#implementation CarClass
- (id) init {
[super init];
NSLog(#"_init: %#", NSStringFromClass([self class]));
engine= [[EngineClass alloc] init];
tires[0]= [[TireClass alloc] init];
tires[1]= [[TireClass alloc] init];
tires[2]= [[TireClass alloc] init];
tires[3]= [[TireClass alloc] init];
return self;
}
EDIT:
this is my dealloc method for the CarClass
- (void) dealloc {
NSLog(#"_deal: %#", NSStringFromClass([self class]));
[engine release];
[tires release];
[super dealloc];
}
Still a bit confused about the retain in the NSArray below, if I add an extra [tires retain] to the CarClass:init then the tires do not get released. However as the code is now the tires release with or without the end retain (i.e.)
tires = [[NSArray arrayWithObjects:
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
nil] retain];
tires = [NSArray arrayWithObjects:
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
nil];
FINAL EDIT: I also thought that without the autorelease on the individual tires that finally releasing the NSArray in the dealloc would release both the array and the objects it points to, this does not seem to be the case.
cheers -gary-
#interface CarClass : NSObject {
EngineClass *engine;
NSArray *tires;
}
.
#implementation CarClass
- (id) init {
self = [super init];
if (self == nil)
return nil;
NSLog(#"_init: %#", NSStringFromClass([self class]));
engine= [[EngineClass alloc] init];
tires = [[NSArray arrayWithObjects:
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
[[[TireClass alloc] init] autorelease],
nil] retain];
return self;
}
You don't always need to use an NSArray for collections. How about this way which has a bit more information about each tyre:
#interface CarClass : NSObject {
EngineClass *engine;
NSDictionary *tiresDictionary;
}
#implementation CarClass
- (id) init {
self = [super init];
if (!self) {
return nil;
}
NSLog(#"_init: %#", NSStringFromClass([self class]));
engine= [[EngineClass alloc] init];
tiresDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:
[[[TireClass alloc] init] autorelease], #"LeftFrontTyre",
[[[TireClass alloc] init] autorelease], #"RightFrontTyre",
[[[TireClass alloc] init] autorelease], #"LeftRearTyre",
[[[TireClass alloc] init] autorelease], #"RightRearTyre",
nil] retain];
return self;
}
This way you still have a collection class, but rather than try and remember which index of an array refers to which tyre, you have a dictionary with descriptive keys so you can refer to each tyre by a name.
I would change Nikolai's example a bit. Since I do not want to add autorelease and retain where none is needed, less code is always less bug-prone code.
#interface CarClass : NSObject {
EngineClass *engine;
NSArray *tires;
}
#implementation CarClass
- (id) init {
self = [super init];
if (self) {
NSLog(#"_init: %#", NSStringFromClass([self class]));
engine= [[EngineClass alloc] init];
tires = [[NSArray alloc] initWithObjects:
[TireClass new], [TireClass new], [TireClass new], [TireClass new], nil];
[tires makeObjectsPerormSelector:#selector(release)];
}
return self;
}
The [tires makeObjectsPerormSelector:#selector(release)]; can be scary, but is useful and also very performant. A slightly less performant way, but maybe more clear would be to let the TireClass implement a factory method, and create autoreleased objects from that one. Like so:
+(TireClass)tire;
{
return [[self new] autorelease];
}
Also please stop naming your classes "Something"Class, a kitten dies if you do :)