I've got a view controller that after leaving the stack, shows a memory leak in the Leaks instrument. After reading lots of posts about the NSDateFormatter bug, and implementing the setDateFormat 'Z' workaround, I'm still leaking memory (according to Instruments).
In my header:
NSDateFormatter *dfm;
...
#property (nonatomic, retain) NSDateFormatter *dfm;
In my implementation:
#synthesize dfm;
...
- (void) viewDidLoad {
[super viewDidLoad];
dfm = [[NSDateFormatter alloc] init];
[self.dfm setDateFormat:#"h:mma Z"]; // leaks with & without this line
}
...
- (void)viewDidUnload {
//SOLUTION: This method was never being called. Needed to use dealloc, per the answer below.
[dfm release];
self.dfm = nil;
[super viewDidUnload];
}
Anything stand out as incorrect? The only thing I do with dfm in this class is call stringFromDate in a few places to return autoreleased strings that I use with UILabels.
Thanks in advance.
You can't rely on viewDidUnload to be called. You also need:
- (void)dealloc {
self.dfm = nil;
// whatever else you need
[super dealloc];
}
You only need to self.dfm = nil because the default synthesized setter will do the release.
Related
This question already has answers here:
app crash in the dealloc
(2 answers)
Closed 9 years ago.
I'm facing small problem,
I declare an array in .h file and allocate it in viewDodLoad method. In dealloc method I check if array not equal to nil then array=nil. But it's crashing in iOS 5.1.1. I can't understand reason for this crash.
My code,
#interface SampleApp : UIViewController
{
NSMutableArray *objArray;
}
#end
#implementation SampleApp
- (void)viewDidLoad
{
[super viewDidLoad];
objArray=[[NSMutableArray alloc]init];
}
-(void)dealloc
{
[super dealloc];
if (objArray!=nil)
{
[objArray removeAllObjects];
[objArray release];objArray=nil;
}
}
Add [super dealloc]; at the end of dealloc method and not at beginning. It is recommended by Apple in its documentation for dealloc method.
When not using ARC, your implementation of dealloc must invoke the superclass’s implementation as its last instruction.
Modify your code as below,
-(void)dealloc
{
if (objArray!=nil)
{
[objArray removeAllObjects];
[objArray release];objArray=nil;
}
[super dealloc];
}
Also, you need not call [objArray removeAllObjects] when you are releasing the entire array. When array is released, internally it will call release on all contained objects.
Hope that helps!
[super dealloc] method must be call in end of this method. Because you can not access variables of the superclass anymore because they are released when you call [super dealloc]. It is always safe to call the superclass in the last line.
-(void)dealloc
{
// ----------- your stuff ------------
[super dealloc];
}
With manual memory management, your -dealloc method looks as follows:
-(void)dealloc
{
[objArray release]; // objArray *may* be nil, and this is
// sufficient to release all elements as well.
// call super at the end
[super dealloc];
}
Additionally, you have a potential memory leak in your method -viewDidLoad. If you do it like your example:
- (void)viewDidLoad
{
[super viewDidLoad];
objArray=[[NSMutableArray alloc]init];
}
you may assign objArray a new pointer even if objArray already holds a valid object. The new pointer value will simply override the old, and thus you cannot release the old anymore.
One way is to check whether objArray is not nil and then release it before assigning it a new value:
- (void)viewDidLoad
{
[super viewDidLoad];
if (objArray) {
[objArray release], objArray = nil;
}
objArray = [[NSMutableArray alloc]init];
}
The better approach however is to employ "lazy initializing properties":
First, define an "internal property" for your array (unless you want the array publicly accessible). In your .m file:
// In your implementation file define a private property in a class extension:
#interface SampleApp ()
#property (nonatomic) NSMutableArray* objArray;
#end
#implementation SampleApp
#synthesize objArray = _objArray; // this will create the setter
-(void)dealloc
{
[_objArray release];
[super dealloc];
}
// Lazy init property: (this is the getter)
- (NSMutableArray*) objArray {
if (_objArray == nil) {
_objArray = [[NSMutableArray alloc] init];
}
return _objArray;
}
- (void) viewDidLoad {
[super viewDidLoad];
// When needing the array, simply *and always* access it
// through the property "self.objArray":
NSUInteger count = [self.objArray count];
}
...
Lazy initialization of properties are quite handy. Basically, you won't worry anymore if they are initialized or not - they simply are, when you use the property accessor.
I am using following code to create NSMutableArray. When I run the same in “Profile” mode, it is showing a memory leakage.
SampleArray.h
#interface SampleArray: NSObject {
}
#property (assign, retain) NSMutableArray *array;
#end
SampleArray.m
#import "SampleArray.h"
#implementation SampleArray
#synthesize array;
-(void) viewDidLoad {
self.array =[ [NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
[self.array release];
}
#end
When I am using autorelease, then I can’t able to access the same in other function or method and return null value. Please help me to find the issue.
releasing this array in viewWilLDisappear is not a good idea, you should release in the dealloc function. You should worry about over-releasing this item and causing a program crash since viewWilLDisappear may get called multiple times during the lifetime of this ViewController.
Anyhow, you are double retaining the item beacuse your property has a retain on it (and make it nonatomic, not assign), add an autorelease to your alloc/init:
self.array =[[[NSMutableArray alloc] init] autorelease];
and move
[array release];
to your dealloc function. Or convert to ARC and don't worry any longer...
Try setting it to (nonatomic, retain), then autoreleasing.
It is better to handle memory de-allocation in your -dealloc() and set your array to nil to be more secure in your -viewDidUnload()
so it will be:
-(void) viewDidUnload
{
self.array = nil;
}
-(void) dealloc
{
[array release];
[super dealloc];
}
and like other people said, declare your property as (nonatomic, retain) instead of (assign, retain)
First of all I'm assuming that you are using
#property (nonatomic, retain) NSMutableArray *array;
use this
-(void) viewDidLoad {
array =[[NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
[array release];
}
I will recommend you to use dealloc instead of viewWillDisappear
-(void) dealloc {
[array release];
[super dealloc];
}
Explanation of your code
-(void) viewDidLoad {
// here you are allocating a mutable array thus retain count becomes one
// then you are assigning it to the property which is retain and thus retains it
// making the retain count 2
self.array =[ [NSMutableArray alloc] init];
}
-(void) viewWillDisappear:(BOOL)animated {
// here you are releasing it so its retain count becomes 1 from 2
// thus shows memory leak
[self.array release];
}
Anyone able to help re what is the source of the leaky object for this code:
My application compiles without any ANALYZE issues. When I run PROFILER and look at Memory Leaks I see leaks appears. One of these leaks is in my WeekendEvent object. There are 3 Leaked Block row items in instruments per the below (I've noted in the code where these point to):
Malloc +1
Retain +2
Release +1
Question - I assume this implies there is a release, however where would this leak be from. The segments of my code that clicking through on instruments highlights is below. To me it seems OK in that:
the WeekendEvent I create I release after passing into the addWeekendEvent method
in the addWeekendEvent it just adds it to a NSMutableArray, and hence I thought the arrange does any memory management for it's object it contains
I do release the NSMutableArray in the dealloc too
Key Source Code Bits & What Instuments Highlights
// ------Weekends Method (plural)-----
WeekendEvent *weEvent = [[WeekendEvent alloc] init]; // [INSTRUMENTS - 87.5%]
[week addWeekendEvent:weEvent]; // [INSTRUMENTS - 12.5%]
[weEvent release];
//------Weekend *.h ------------
#interface Weekend : NSObject {
NSMutableArray* _events;
}
- (void)addWeekendEvent:(WeekendEvent*)weEvent;
#property (nonatomic, retain) NSMutableArray* events;
#end
//------Weekend *.m -------------
- (void)addWeekendEvent:(WeekendEvent*)weEvent {
[self.events addObject:weEvent];
}
- (void) dealloc {
[_events release];
[super dealloc];
}
EDIT: Some additional code re how the "week" variable above was created/used - so in the Weekends Method the code I posted was within a for loop - the code with the for loop shown therefore was:
for (Weekend *week in self.items) {
// do pass "week.start" to some methods (which is an NSDate) - don't think this would be relevant though?
WeekendEvent *weEvent = [[WeekendEvent alloc] init]; // [INSTRUMENTS - 87.5%]
[week addWeekendEvent:weEvent]; // [INSTRUMENTS - 12.5%]
[weEvent release];
}
// Note - self.items I checked is "released" in the dealloc method
EDIT 2 - Just to confirm, it is an "WeekendEvent" instance that Instruments highlights in it's "leaked objects" column. Just in case this wasn't clear.
EDIT 3 - Re how I setup the items variable - key code bits are:
#interface Weekends : NSObject {
NSMutableArray* _items;
}
#property (nonatomic, retain) NSMutableArray* items;
#synthesize items = _items;
- (void) dealloc {
[_items release];
[super dealloc];
}
The memory management in the code you show is correct, assuming that the rest of your Weekend class looks something like this:
#synthesize events = _events;
- (id)init {
if ((self = [super init]) == nil) { return nil; }
_events = [[NSMutableArray alloc] initWithCapacity:0];
return self;
}
Also, the instruments results match all of your code:
Malloc +1 == WeekendEvent *weEvent = [[WeekendEvent alloc] init];
Retain +2 == [week addWeekendEvent:weEvent];
Release +1 == [weEvent release];
Based on that logic, the most likely candidate is that your week object is not properly released. You haven't shown the code that explains how it was created, but I do notice that the code you did post is for a Weekend class. Are you sure week is not of a different type?
Usually when I create an object and assign it to an instance variable I alloc a temp object, call the iVar setter to retain the object and then release the temp object. However I was looking at init this morning and noticed that if I simply assign the iVar directly, its retained by the alloc whilst also being released correctly when either the setter is called or dealloc is executed. I am just curious if I am understand this correctly?
#property(nonatomic, retain) CLLocationManager *locationManager;
.
#synthesize locationManager;
// VERSION 001
- (id)init {
self = [super init];
if(self) {
CLLocationManager *tempManager = [[CLLocationManager alloc] init];
[self setLocationManager:tempManager];
[tempManager release];
}
return self;
}
// VERSION 002
- (id)init {
self = [super init];
if(self) {
locationManager = [[CLLocationManager alloc] init];
}
return self;
}
- (void)dealloc {
[locationManager release];
[super dealloc];
}
As far as the memory management goes both solutions are fine. But you might want to prefer the direct access in init and dealloc, see this related question.
Version 002 is the Apple approved answer because the pitfalls of using an accessor in init are theoretically worse. Basically, a subclass could choose to override your accessor and then you'd be sending a message to a subclass object that is not yet initialised.
However, everywhere else except init and dealloc, use version 001.
I have a singleton class and the lines in the init method cause memory leak, and I don't kwno why...
this is my implementation
static timerController *sngTimer = nil;
#implementation timerController
#synthesize repeatingTimer;
#synthesize dateComp;
#synthesize bPause;
+(timerController *) singletonTimer
{
#synchronized(self){
if (sngTimer == nil )
{
sngTimer = [[timerController alloc]init];
}
}
return sngTimer;
}
-(id)init
{
self = [super init];
if (self != nil) {
dateComp = [[NSDateComponents alloc] init]; ///this line cause memory leak
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; ///this line cause memory leak
[dateComp setCalendar:gregorianCalendar]; ///this line cause memory leak
[gregorianCalendar release];
bPause = FALSE;
}
return self;
}
I don't know how you're detecting the leak, but most likely whatever tool you're using notices that you don't have a dealloc method to release the object you create there. You probably should have it for completeness, but as long as the class is only used as a singleton, it doesn't really matter.
It's not a leak. A singleton stays around forever (usually), so it's supposed to remain in memory.
Chuck's answer is correct. Implement a -dealloc method, and inside it, set the dateComp property to nil or release the corresponding ivar. -dealloc will never get called, but it will shut up the static analyzer.
Here's a good article on some of the subtleties of singletons.