I just familiarise myself with the CLLocationManager and found several sample class definitions that contain the following init method:
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
}
return self;
}
- (void)dealloc {
[self.locationManager release];
[super dealloc];
}
I don't understand why the iVar would be autoreleased. Does this not mean it is deallocated at the end of the init method?
I am also puzzled to see the same sample codes have the iVar release in the dealloc method.
Any thoughts?
'
The locationManager is a property that is likely set with the retain attribute.
Basically, if you only write:
self.locationManager = [[CLLocationManager alloc] init];
the left-side self.locationManager setter retains a reference to the allocated CLLocationManager. But the right-side CLLocationManager reference is itself never released. The retain count for this manager never hits zero and the object never goes away — this causes a memory leak.
There are two ways to address this. Either autorelease the allocated object as you've seen in the code snippet you cited — or you assign the allocated object to a temporary variable, retain the temporary variable to the locationManager property, and then explicitly release the temporary variable:
CLLocationManager *_temporaryReference = [[CLLocationManager alloc] init];
self.locationManager = _temporaryReference; // this is retained
[_temporaryReference release];
Both approaches are equivalent, in terms of memory management. Some prefer this second approach because they don't like waiting for the autorelease pool to be "emptied", especially on a low-memory device like an iPhone, and this provides tighter control over an object's lifespan.
Apple's Objective-C Programming Language documentation explains this attribute in more detail.
There is an alternative without the temporary variable or the autorelease:
locationManager = [[CLLocationManager alloc] init];
Without using the self.locationManager you are not calling the setter method of the class for that variable and as a result not increasing the retain count to 2. The compiler changes these assignments into [self setLocationManager: locationManager];. This assumes that you have prototyped the variable as retain.
If it is a class variable (which it is) you can just make the assignment. It is debatable whether this is good coding practice but in my opinion it depends on where it is in the class initiation.
If your self.locationManager is a property that retains it, then it sets the retain. By doing alloc you do set the retain count to +1, which means that by the end of the function it's +2. When you say autorelease, it'll be +1 (because of the retaining property). You could also explicitly release it after setting it to the property, but what you're doing is less code and easy to read.
Related
In my class dealloc method I have
- (void) dealloc
{
[searchField release];
[super dealloc];
}
Where searchField is defined in the class variables.
#interface SearchCell : UITableViewCell
{
UISearchBar *searchField;
id delegate;
}
The class is used with the following way:
if (indexPath.section == 0)
{
SearchCell *mycell = [[SearchCell alloc] init];
[cell setDelegate:self];
return [mycell autorelease];
}
searchField is created here:
- (id) init
{
self = [super initWithFrame:CGRectZero];
[self create];
return self;
}
- (void) create
{
searchField = [[UISearchBar alloc] initWithFrame:CGRectZero];
searchField.autocorrectionType = UITextAutocorrectionTypeNo;
[self addSubview:searchField];
}
Do I need to use [searchField release]; in my dealloc? The application crashes with message: "*[UISearchBar respondsToSelector:]: message sent to deallocated instance *".
No, don't release it there. Since you return it with "autorelease", the next run through your event loop will automatically decrease the retain count.
When you finally hit your "dealloc" method, the retain count is already 0 and your app will raise an exception.
You need to be aware of object ownership rules. In manual retain & release environment (as opposed to ARC) the rules for Objective-C objects can be remembered with the acronym NARC.
If you have a reference to an object that you created fresh using new or alloc, or any object that you called retain on, or any object you created by calling copy or mutableCopy on another, or any object created by any methods that start with any of these names (e.g. newInstance), then
you own that object and before you are deallocated you must release it.
But, if you didn't do any of those things, then you do not own that object, and must not release it. source
In your case - you don't show the code where you set the value searchField, but from the crash I'd imagine you never take ownership of the object. Show the code where you assign to searchField and we'll all know for sure.
EDIT: You do take ownership by creating it with alloc. You need to keep the release there in dealloc. Is it being released from somewhere else? Or is the cell itself possibly getting overreleased?
I come from a C background, and as many of you are aware Objective-C is derived from C. I assumed the memory management concepts were similar. I am getting a warning about a potential memory leak however what is strange is that i am releasing the object after an alloc. Take a look at this example:
self.cardCellArray = [[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards];
and in the dealloc:
- (void) dealloc
{
[super dealloc];
[self.cardCellArray removeAllObjects];
}
The memory leak messages I am getting are:
Method returns an Objective-C object with a +1 retain count
and
Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1
Can anybody spot what I am doing wrong here?
I'm assuming that the cardCellArray property is an owning reference (ie. retain or copy).
self.cardCellArray = [[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards];
This should be:
self.cardCellArray = [[[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards] autorelease];
Or even:
cardCellArray = [[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards];
To ensure the memory management is correct.
Also, the dealloc method should be:
- (void)dealloc
{
[cardCellArray release];
[super dealloc];
}
This assumes that the instance variable for the cardCellArray property is named cardCellArray.
You are not releasing the array but rather just emptying it.
Also note that I moved the [super dealloc] call into the last line, this is because the object with its instance variables gets completely freed later in the dealloc chain and thus you would try to access freed memory.
- (void) dealloc
{
[cardCellArray release];
[super dealloc];
}
Another thing: You are using self.cardCellArray =, depending on how your #property for the ivar looks like, you might have to remove the self. part as it retains the object (or you have to manually release it later). #property's that retain the objects are copy and retain
check if the property cardCellArray is retain or copy. if so, when you are calling self.cardCellArray, the object you set to property cardCellArray get retain count increased by 1.
creating object using alloc & init (such as initWithCapacity:) return a object with retain count 1, because you have called a alloc method here.
While creating object without call alloc such as [NSMutableArray arrayWithCapacity:] will return a autorelease object(it will auto decrease it's retain count by 1 when needed),you can consider it has retain count 0.
in method dealloc, you should call [self.cardCellArray release], this will automatically remove all object the array retain.
Your code here generate a retain-count-1 object after
[[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards]
and this object's retain count become 2 when you call
self.cardCellArray = xxx
but in dealloc you didn't decrease cardCellArray 's retain count, then leaks occurred.
So Change your code to
self.cardCellArray = [[[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards] autorelease];
autorelease will automatically decrease retain count when needed.
or self.cardCellArray = [NSMutableArray arrayWithCapacity:kTotalNumberOfCards];
or
NSMutableArray *_array = [[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards];
self.cardCellArray = _array;
[_array release];
or
cardCellArray = [[NSMutableArray alloc] initWithCapacity:kTotalNumberOfCards];
//this helps because it doesn't call `[self setCardCellArray]` which generate +1 retain count.
finally, remember to release cardCellArray too in dealloc method
Yep, as JustSid suggests you are double-retaining the array and never releasing it.
While Objective-C heap management has it's roots in C, the way individual objects are managed is entirely different.
You don't say how the property cardCellArray is defined, but presumably it's defined as retained, such that, when you assign to self.cardCellArray, you're really executing the method setCardCellArray, and that method "retains" the object. But it's already retained as a result of your alloc call, so now it's retained twice.
Then, in the dealloc method you don't release it at all. You can release the object by doing [cardCellArray release]; or by doing self.cardCellArray = nil;. Either will release it (but only once -- you need to solve your problem with the double retain).
You do not need to do the removeAllObjects call. When you release an object (and the retain count goes to zero) the object's dealloc method is called and it does the releases appropriate for the objects it references.
(And as Sid suggests, do the [super dealloc] call last.)
(But of course, everything above is out the window with ARC, where you get to worry about an entirely new and different set of things you can screw up.)
Please take a look at the following code.
XmlManipulatorObject=[[xmlManipulator alloc] init];
self.QuestionMutableArray=[[XmlManipulatorObject ReadXml] init];
self.dictionary=[[NSMutableDictionary alloc]init];
self.dictionary=[QuestionMutableArray objectAtIndex:reloader];
in my dealloc method i need to release all the objects i am using above.What should be the way?
I tried with the following but having BAD_ACCESS :
-(void)deallocAll
{
[self.dictionary release];
[self.XmlManipulatorObject release];
[self.QuestionMutableArray release];
}
and the properties are as below :
#property(nonatomic,retain)NSMutableDictionary *dictionary;
#property(nonatomic,retain)NSMutableArray *QuestionMutableArray;
#property(nonatomic,retain)xmlManipulator *XmlManipulatorObject;
Ok you have a number of things wrong/ bad ideas happening here:
Variable and method names should start with a lowercase letter. This helps with readability and avoids confusion with class names. So XmlManipulatorObject should be xmlManipulatorObject, ReadXml should be readXml, etc.
When you create an instance of a class, you either should autorelease it or manually release it. For example:
self.dictionary=[[[NSMutableDictionary alloc] init] autorelease];
or
NSMutableDictionary *myDic = [[NSMutableDictionary alloc]init];
self.dictionary=myDic;
[myDic release];
From the above it also appears that you don't know about the way that properties handle retains and releases. Do some reading about properties.
Sometimes it is far better to release your objects immediately after your done using them rather than at the dealloc method.
Also you should probably use the default dealloc method.
Also since you never called the dealloc super method you wont be releasing any memory.
-(void)deallocAll
{
[self dealloc];
[self.dictionary release];
[self.XmlManipulatorObject release];
[self.QuestionMutableArray release];
}
I would even go as far to change this from deallocAll to just dealloc.
drekka is right. You should note the below point too,
If you are using synthesized properties, set your variable to nil instead of releasing it.
self.yourObject = nil;
This will send the setter method 'nil' as a parameter, and your object will be released by the setter method.
i dont know what is the purpose of deallocAll. Well the best way i learned so far for that case:
NSObject *ob = [[NSObject alloc] init];
self.myObject = ob;
[ob release];
And in dealloc
-(void)deallocAll{
[super dealloc];
[myObject release];
}
#implementation TestClass
- (id) init
{
string = [[NSString alloc] init];
return self;
}
- (void) release
{
[string release];
}
#end
#implementation MainScreen
- (void) addItems
{
[myMutableArray addObject:[[[TestClass alloc] init] autorelease]];
}
- (void) release
{
[myMutableArray release];
}
My Question is when we release the myMutableArray, will it call the release method of TestClass or not?
No, that's not how Cocoa memory management works. When you add the object to the array, the array expresses that it owns the object by sending the -retain message. The array keeps this ownership until it itself disappears (i.e. is deallocated), then it no longer needs the object and sends it -release to relinquish ownership. The array does not need to retain or release the objects every time it is retained or released.
To summarise: objects retain other objects when they need to take ownership of them, and release them when they no longer need that ownership.
This points to your memory management of the string ivar being incorrect. You correctly take ownership of a zero-length string in -init (where I'm using "correctly" in a very loose sense), but then every time your object is released it releases the string. Consider:
TestClass *obj = [[TestClass alloc] init];
[obj retain];
[obj release];
[obj release];
the above is likely to crash (and if it doesn't, you're very unlucky). You should release the string in -dealloc, when your object finally doesn't need it any longer. If you change the object referred to by the ivar, you also have to change the ownership.
Never ever override -release! What you want to override is -dealloc! And in there you have to call [super dealloc]
Please read http://developer.apple.com/library/mac/documentation/cocoa/conceptual/memorymgmt/MemoryMgmt.pdf
And to your question, if your array gets deallocated, every object in the array is sent a release message.
You should be overwriting the - (void) dealloc method, not the -(void) release one; and always call [super dealloc] at the end.
Yes, releasing an NSMutableArray releases the individual objects too.
just as
[myMutableArray addObject:[[[TestClass alloc] init] autorelease]];
will increment retainCount to the TestClass instance
so will release decrement the retainCount for all objects in the array
note that dealloc is the method to implement in your custom class, it is called when your object is released.
This is an offshoot from a previous question, is this bad practice (using the property to set iVars)?
// Designated initializer 001
- (id)initWithName:(NSString *)newName andType:(NSString *)newType {
self = [super init];
if(self) {
[self setName:newName];
[self setType:newType];
}
return self;
}
or should I be using ...
// Designated initializer 002
- (id)initWithName:(NSString *)newName andType:(NSString *)newType {
self = [super init];
if(self) {
name = [newName retain];
type = [newType retain];
}
return self;
}
I have been using version 001, but have been led to believe that using properties to access iVars in either init or dealloc is bad practice.
EDIT: Added retain to version 002
Gary.
Yes, Apple discourages using accessors in init or dealloc, because they can have side effects beyond merely setting an instance variable. These are obviously undesirable in an uninitialized or destroyed object.
Exact quote from the docs: "The only places you shouldn’t use accessor methods to set an instance variable are in init methods and dealloc."