#interface foo: NSObject
#property (nonatomic, retain) NSMutableArray *aMutableArray;
#end
#implementation
#synthesize aMutableArray
-(void)somefunction {
// Illustration
self.aMutableArray = [[[NSMutableArray alloc]init]autorelease];
self.aMutableArray = [[[NSMutableArray alloc]init]autorelease];
self.aMutableArray = [[[NSMutableArray alloc]init]autorelease];
}
#end
I have done code similar code to this in other parts of my program, but I needed to be certain that this does not cause a memory leak. With my understanding of autorelease, this object is released correctly right?
[EDIT - added question]
One question though: the property above has a retain attribute, so when the compiler creates the setter function, the setter code will look something like this:
somecode..
retain newObj
release oldObj
somecode..
in the code above, I assigned 3 objects to aMutableArray.
Each time they are assigned, the setter function did a retain on the newObj and a release on the oldObj. So, since the setter method already did a release, will there be a problem when the autorelease kicks-in to release the object a second time?
Yes, it will be released correctly if you also release it dealloc method:
- (void) dealloc{
[aMutableArray release];
[super dealloc];
}
Note also that you can shorten your code using equivalent convenience +array method of NSMutableArray:
self.aMutableArray = [NSMutableArray array];
Related
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 have few questions to ask about the following class
#import <Cocoa/Cocoa.h>
#interface SomeObject {
NSString *title;
}
#property (retain) NSString *title;
#end
implementation SomeObject
#synthesize title;
-(id)init {
if (self=[super init])
{
self.title=[NSString stringWithFormat:#"allyouneed"];
}
return self;
}
-(void)testMethod{
self.title=[[NSString alloc] init] ;
}
-(void)dealloc {
self.title=nil;
[super dealloc];
}
In the .h file do we need to declare the title and sub when we add the property. is it not enough to add the #property (retain) NSString *title; line.
2.Do i need to autorelease both assignment to title in the init and testMethod. if So why?
Can some one explain these things to me.
1-
You don't need to declare the iVar in the header. You might also use
#synthesize myVar = _myVar;
if you want to go for a different iVar name
2-
Declaring a property "retain" means that every time you assign the property with a new object, it automatically releases the previous object and retain the new one.
Therefore, if you use a convenience method like stringwithFormat, the property will retain that object for you.
If you want to use alloc-init, for me the best way to do is:
NSString *str = [NSString alloc] init];
self.title = str;
[str release];
Besides, it is right to assign nil to the property in the dealloc because the property will release the object it has, and it calls retain on nil which doesn't do anything
1.No need to declare title in .h, declaring property is enough.
2.when you are using self.title in init, you do not have to autorelease it.But when you initialize it in testMethod, you need to autorelease it because you have declare the property as retain.And do not forget to release title in dealloc.
you don't need to add as it is done automatically (Since Xcode 4 I guess).
in init- you don't as it already returns an autoreleased object..
where as in testMethod you need to since you are allocating it..
you always have to release any object which you create using alloc , copy or new .... AMEN.. :)
Be aware it is not considered a good practice to use accessor methods in initializer methods and dealloc method. Do check out this answer: Why shouldn't I use Objective C 2.0 accessors in init/dealloc?
Also in Apple's memory management guide: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html
I have the following questions about allocating properties in Objective-C,
if I have the following property:
#property (nonatomic, retain) NSArray *arr;
#synthize arr=_arr;
should I allocate this array like:
arr=[[NSArray alloc]init];
and if I should to, where is the best place to to allocate it?
I know I should release it, but retaining a property will increase its retain count by 1 and allocating it will increase it by another 1, am I right.
You can allocate the array in two ways:
Set the ivar directly with a retained value, like this:
_arr = [[NSArray alloc] init];
Set the property with an autoreleased value like this:
self.arr = [NSArray array];
You can do this in your class's init method, although you've not said what superclass this is using so I'm not sure how the init method should look. If it's an NSObject, it will look like this:
- (id)init
{
if ((self = [super init]))
{
self.arr = [NSArray array];
}
return self;
}
But if it's a UIViewController, you'll need to use initWithNibName:bundle, like this:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil
{
if ((self = [super itWithNibName:nibNameOrNil bundle:bundleOrNil]))
{
self.arr = [NSArray array];
}
return self;
}
Then you need to release it in your dealloc method, like this:
- (void)dealloc
{
[_arr release];
[super dealloc];
}
However, you should bear in mind that NSArrays can't be changed once they're created, so you probably either want to initialise it with some objects, like this:
self.arr = [NSArray arrayWithObjects:object1, object2, nil];
Or if you want to add objects to it later, you should define it as an NSMutableArray, like this:
#property (nonatomic, retain) NSMutableArray *arr;
And init it with:
self.arr = [NSMutableArray array];
That will let you add objects to it later.
By the way, if you get errors in your dealloc method, it probably means that your project is using ARC, which is a new technology in iOS 5 that means you don't need to write release and retain statements any more.
If you aren't using ARC I suggest you do so because it will save you having to worry about this retain/release stuff - any iOS developer who is just starting out now should really use ARC for every project, but because it was only introduced in iOS 5, a lot of the Objective-C books don't cover it.
My object is not getting released from memory so I override retain method and put a breakpoint in to see where in code it gets retained.
Every time the object is referenced using a property accessor the retain method is called. Why would this be happening?
color = self.myobject.color
calls retain.
The synthesized property accessor for retained properties looks something like this:
- (UIColor *)color
{
return [[_color retain] autorelease];
}
Therefore, your retain method is called, but it's balanced with an autorelease.
See this code snippet in the Objective-C Programming Language Guide for an example of how a synthesized accessor might look (the locking part doesn't apply in the nonatomic case, but the retain-autorelease is the same).
Because you probably declared your property as retain or copy:
#property (nonatomic, retain) MyObject* myobject;
If you #synthesize that, the compiler will generate code that looks more or less like:
- (void) setMyobject: (MyObject *) value
{
if (value != myobject)
{
[myobject release];
myobject = value;
}
}
Each time you assign to self.myobject, that method is invoked with the new object as value parameter. It should release the old object, but the last object added is retained. You'll have to release it in your dealloc. And you should release what you allocated, so the pattern is:
MyObject *myObj = [[MyObject alloc] init];
self.myobject = myObj;
[myObj release];
Items returned from a method are usually autoreleased, so you should not release those:
MyObject *myObj = [someOtherObject someMethod: 17];
self.myobject = myObj;
// Do NOT release myObj!
Update
See #omz's explanation. I misread and was talking about the setter. Your getter does a retain too, but that is immediately paired with an autorelease. Since you only log the retains, it only looks as if you have leaks.
I'm writing an iPhone app. I have a header file that looks like this:
#interface EditTagsViewController : UITableViewController {
NSMutableArray *allTags;
NSMutableArray *selectedTags;
NSInteger currentFavorite;
}
#property (nonatomic, retain) NSMutableArray *allTags;
#property (nonatomic, retain) NSMutableArray *selectedTags;
#property (nonatomic) NSInteger currentFavorite;
#end
In the implementation file, my viewDidLoad method looks like this:
- (void)viewDidLoad {
NSMutableArray *aTags = [[NSMutableArray alloc] initWithArray:[Tag findAllTags]];
self.allTags = aTags;
[aTags release];
NSMutableArray *sTags = [[NSMutableArray alloc] initWithArray:[Tag findByFavoriteId:currentFavorite]];
self.selectedTags = sTags;
[sTags release];
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNewTag:)];
self.navigationItem.rightBarButtonItem = add;
[add release];
[super viewDidLoad];
}
Here is my dealloc method:
- (void)dealloc {
[allTags release];
[selectedTags release];
[super dealloc];
}
What's confusing to me is that when I run the app both in the simulator and on the device itself, using Instruments (memory leaks), it tells me that this line in my viewDidLoad method is leaking an array:
self.selectedTags = sTags;
It's confusing because I'm using the exact same technique with 2 different variables, and yet no leak is reported with the first one.
I feel like I'm missing something obvious here. Any ideas?
Your code looks correct to me. Is it possible that one of [Tag findAllTags] or [Tag findByFavoriteId:] is leaking? Are you making sure to set self.allTags and self.selectedTags to nil in dealloc?
Be mindful of the difference between saying self.allTags = ... and allTags = .... Because allTags is a property and has the retain attribute, whenever you assign via self.allTags = ..., it implicitly calls the setter method [self setAllTags:...], which invokes retain on the new value and release on the old value (if any). You're doing it correctly in this code sample, but if elsewhere you're assigning straight to allTags (without the self.), you're not releaseing the old value, which may be the source of the leak. Likewise for selectedTags.
Have a look at findByFavoriteId is there a retain there? That is the only difference I can see between the aTags and sTags are used in your example