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.
Related
#interface Foo : NSObject
#property (nonatomic, retain) Bar * bar;
#end
#implementation Foo
#synthesize bar = _bar;
- init {
self = [super init];
if (self) {
_bar = [[Bar alloc] init];
// Or
_bar = [[[Bar alloc] init] autorelease];
}
return self;
}
- (void)dealloc {
[_bar release];
[super dealloc];
}
#end
When I run the analyzer, both
_bar = [[Bar alloc] init];
and
_bar = [[[Bar alloc] init] autorelease];
are fine.
Which one I should use?
You should use the first. It creates a retained object, whereas the second "autoreleases" that retain.
The important consideration is that you're assigning it to instance variable _bar. If you were, instead, assigning it to property self.bar, then the retain directive in the property declaration would cause the object to be retained, so assigning an autoreleased value would be appropriate. But since you're assigning to the "bare" instance variable instead, you need to handle the retain yourself, so you need the first form.
PS: I'm a bit surprised that the analyzer doesn't complain about the second version.
PPS: It should be noted that the choice here is highly context dependent. But you included enough context (the property definition) to make the choice. Without seeing the property definition (or other info, in the case of a non-property) it would be hard to say.
The autorelease version is not correct and may cause crashes in some situations—your first line results in _bar having a retain count of 1, and thus sticking around until it's released in -dealloc when you no longer need it.
The second line, however, releases the object soon-ish (specifically, at the end of the run loop), and thus could cause it to disappear when you still need it.
Read Apple's Guide on Memory Management for more information.
Let say i have an class named as MyTestClass.h.
Class structure is look like
#interface MyTestClass : NSObject {
NSString *testString;
}
#property (nonatomic, retain)NSString * testString;
#end
.m file
#implementation MyTestClass
#synthesize testString;
-(id) init{
[self setTestString:#""];
return self;
}
-(void)dealloc{
[self.testString release];
testString = nil;
[super dealloc];
}
#end
Now i created an object of MyTestClass and assigned testString twice
MyTestClass * myTestClass = [[MyTestClass alloc] init];
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
Now i think, two times my testStrings memory is leaked!! (one through init() and another one through my first setTestString method)
Am i correct? or will #property (nonatomic, retain) handle/release previous allocated memory?
or ,in this kind of cases ,will i need to override the setTestString() in MyTestClass.m like below code
-(void)setTestString:(NSString *)tempString{
[testString release];
testString = nil;
testString = [tempString retain];
}
Any help on this question is appreciated.
Thanks.
Any help on this question is appreciated.
I'll take this as a licence to make sone observations not necessarily directly related to your question.
Firstly, if you declare a retain property (as you have done) and synthesize it, the automatically generated getters and setters handle memory management correctly for you.
If you manually create setter (which you are allowed to do even with an #synthesize existing), you have to do the memory management yourself. Use either of trojanfoe's examples.
The setter in your question contains a bug in that if testString == tempString i.e. you assign the value of the property to itself, you could end up with assigning a dangling pointer to the property because you effectively release tempString and then retain it.
This is an implementation detail that you an safely ignore, but string literals e.g. #"blah" are compiled into the executable and will never be deallocated no matter how many times they are released. So, with your example, even if the setter did not do correct memory management, there will be no leak.
By the way, the normal pattern for an init method is
-(id) init
{
self = [super init];
if (self != nil)
{
// init stuff
}
return self;
}
or logical equivalent.
You should get into the habit of using it because you need to call the super class's init method and it is allowed to change the value of self, even to nil.
Also, while it is very good practice normally to set the object reference to nil after releasing it, in both cases when you do it, it is unnecessary. the first time, the variable is about to go out of scope and the second time you immediately assign it from some other object.
It's not a leak. Synthesized variable are correctly handled.
A synthesized method is implemented in this way (for a retain keyword)
#property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;
- (void)setString:(NSString*)newString
{
if (newString != _string) {
[_string release];
_string = [newString retain];
}
}
Of course this is a leak:
- (void)aMethod //of my class with string property
{
NSString *aString = [[NSString alloc] initWithString:#"hello"];
self.string = aString; //retain count of 2
self.string = #"hello2"; //retain count of 1 for aString
//now I don't release aString.... leak
}
If you use the auto-generated setter (in your case, setTestString:, which is also called by self.testString = ...;), the previous value of a retain property is released before being set. So no, there is no leak in the code you posted above.
The synthesized setter method should do the right thing. Here's an example of it's implementation:
- (void)setTestString:(NSString *)tempString
{
[tempString retain];
[testString release];
testString = tempString;
}
or:
- (void)setTestString:(NSString *)tempString
{
if (tempString != testString)
{
[testString release];
[tempString retain];
testString = tempString;
}
}
the dealloc is only called when the instance is destructed.
if you do :
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
in the same block, you're juste calling twice the setter. there is no memory leak.
When you use #synthesize on a property that specifies retain, the setter that's generated will handle the retain/release correctly for multiple assignments. As long as you use self. rather than going directly to the backing variable and do a final release in dealloc you should be fine.
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.
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 create a SinglestonClass in my code but i have a problem.
My variable are initialized in the -init method but when i call the singlestonClass these variable are re-initialize.
Can you help me for create a single initialization for my variable?
thanks.
#implementation SingletonController
#synthesize arrayPosition;
#synthesize arrayMovement;
#synthesize actualPosition;
#synthesize actualMove;
#synthesize stopThread;
+(SingletonController*)sharedSingletonController{
static SingletonController *sharedSingletonController;
#synchronized(self) {
if(!sharedSingletonController){
sharedSingletonController = [[SingletonController alloc]init];
}
}
return sharedSingletonController;
}
//I don't want a re-initialization for these variables
-(id)init{
self = [super init];
if (self != nil) {
arrayPosition = [[NSMutableArray alloc]init];
arrayMovement = [[NSMutableArray alloc]init];
actualPosition = [[Position alloc]init];
actualMove = [[Movement alloc]init];
stopThread = FALSE;
}
return self;
}
-(void) dealloc {
[super dealloc];
}
#end
Your init method should not be called by anyone except for your singleton class itself. That's what the sharedSingletonController method is for. This is your factory method that is responsible for returning the same static instance of your class. I'd also suggest that you rename the static instance of your singleton object and/or the sharedSingletonController selector itself to disambiguate between the two and for cleaner design. In this particular case, it may confuse someone who has to read your code.
Without seeing how the client code is calling on your singleton factory method, it's difficult to decipher where your problem is. We'd need to see the rest of the code including how it's being called. In your client code, you should be using something such as:
SingletonController *sigController = [SingletonController sharedSingletonController];
DO NOT DO:
SingletonController *sigController = [[SingletonController alloc] init];
Read here for more information in the Cocoa Fundamentals Guide.