memory menagement in ios - objective-c

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.

Related

Where the Memory is Leaking because showing leakage

In my Code showing 2 places memory leakage please see and Help me.
1.FIRST
UIButton *push = (UIButton *)sender;
NSString *string = [NSString stringWithFormat:#"%#",[push currentTitle]];
NSArray *chunks = [[NSArray alloc]initWithArray:[stringcomponentsSeparatedByString:#"-"]];
list = [[NSMutableArray alloc]initWithArray:chunks];
(NSMutableArray *list;)
[chunks release];
2.SECOND
Here is The Source Code First
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSURL *url = [[NSURL alloc]initWithString:#"http://www/absdf.com/myXML.xml"];
self.parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
[parser setDelegate:self];
[parser parse];
[parser release];
[url release];
[pool drain];
while i am excuting this code and with this Instruments Tools on line number : 2 show memory leakage with heaviest backtraces.
So please let know the Reason .?
In addition to the other answers your pool should be released
NSAutoreleasePool *pool = [NSAutoreleasePool new];
//... then
[pool release];
Obviously, list = [[NSMutableArray alloc]initWithArray:chunks]; is never released.
self.parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
alloc/init returns a retained object, and if you your parser property is declared with retain attribute, then you are over retaining it. It should be:
self.parser = [[[NSXMLParser alloc]initWithContentsOfURL:url] autorelease];
P.S. Make sure you are doing proper memory management to your list instance variable. Just to be sure you better use properties.
list should be release somewhere, maybe in dealloc
- (void)dealloc {
[list release];
[super dealloc];
}
parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
or
NSXMLParser *tempParser = [[NSXMLParser alloc]initWithContentsOfURL:url];
self.parser = tempParser;
[tempParser release];

Force release an autorelease object

Can I force an Autorelase object by calling a release without autorelease pool like that:
NSString *myString = [[[NSString alloc] init] autorelease];
[myString release];
Normally it's like that:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *myString = [[[NSString alloc] init] autorelease];
[pool release];
The first sample will crash, since the string will get over-released. If you want to have control over the lifetime of your autoreleased objects, the correct approach is what your second sample does – create a local autorelease pool that you can drain when you want.
Your code will crash because global auto release pool will try to release the object later. Results in malloc double free error
You can do this:
NSString *myString = [[[NSString alloc] init] autorelease];
Or this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *myString = [[[NSString alloc] init] autorelease];
[pool release];
But not this:
NSString *myString = [[[NSString alloc] init] autorelease];
[myString release];

Sort NSMutableArray memory leak

My object has a private NSMutableArray items. I am using the following code to sort the objects in items in size order:
-(void)sortItems{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"size" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [items sortedArrayUsingDescriptors:sortDescriptors];
NSMutableArray* newArray = [[NSMutableArray alloc] initWithArray: sortedArray];
[self setItems:newArray];
[sortDescriptor release];
}
Obviously this is a memory leak here, because every time I call sortItems, I am allocing new memory and assigning items to point to it. I've tried releasing the old memory as follows:
NSMutableArray* newArray = [[NSMutableArray alloc] initWithArray: sortedArray];
NSMutableArray* oldArray = [self items];
[self setItems:newArray];
[oldArray release];
But that gives an EXC_BAD_ACCESS error. I've read up on memory handling in objC, and I'm convinced I'm doing something fundamentally wrong here.
Any help would be greatly appreciated!
You're leaking the new array, not the old one:
NSMutableArray* newArray = [[NSMutableArray alloc] initWithArray: sortedArray];
[self setItems:newArray];
[sortDescriptor release];
[newArray release]; // <-- add this
The fundamental rule is that you must release anything that you have allocated, and you normally shouldn't care about keeping things retained for anyone (i.e. [self setItems:]), those who need something retained will do it themselves.
I would also recommend making self.items a mutable array, and using [self.items sortUsingDescriptors:sortDescriptor to sort inplace without creating a copy.
Is there a reason why you cannot release the newArray in your first example?
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"size" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [items sortedArrayUsingDescriptors:sortDescriptors];
NSMutableArray* newArray = [[NSMutableArray alloc] initWithArray: sortedArray];
[self setItems:newArray];
[newArray release];
[sortDescriptor release];

Is [NSMutableString string] same as [[NSMutableString string] autorelease]?

I noticed a piece of code somewhere it does
NSMutableString *myString = [[NSMutableString string] autorelease];
Is it overkill? Shouldn't it be the same as [NSMutableString string]?
NSMutableString *myString = [[NSMutableString string] autorelease];
will lead to a crash if they aren't calling retain on it elsewhere.
[NSMutableString string]
is the same as
[[[NSMutableString alloc] init] autorelease]
Doesn't look right to me. Are you sure that the example you saw is actually doing this?
[NSMutableString string] is equivalent to
[[[NSMutableString alloc] init] autorelease]
So with the example you provided, you would get
[[[[NSMutableString alloc] init] autorelease] autorelease]
which would result in an over release and an exc_bad_access error.

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