#interface Approval : NSObject
{
NSMutableArray *approvalValues;
}
#property (nonatomic,retain) NSMutableArray *approvalValues;
If i do this, do I still need to call `approvalValues = [[NSMutableArray alloc] init] in the init method? I was under the impression that I had to but it is causing a leak. In the dealloc method I am releasing approvalValues
You need to alloc and init approvalValues. The problem seems to be related to the fact that you are over-retaining your object.
Your code probably looks like this:
self.approvalValues = [[NSMutableArray alloc] init];
alloc will return an object with a retainCount of 1, and when using the retain setter it will get bumped to 2. In order to solve it, you might want to autorelease the object before assigning it, making a code that looks like this:
self.approvalValues = [[[NSMutableArray alloc] init] autorelease];
This will end up with an instance variable with a retainCount of only 1, so when you dealloc the object it won't leak.
Yes you still need to alloc/init, however you only release in dealloc method.
In the init method you will often access the ivar directly and initialize it like this:
approvalValues = [[NSMutableArray alloc] init];
In the dealloc you will need a matchin release like this:
[approvalValues release];
It is often recommended to access the ivars directly in the init and dealloc method to avoid any side effects caused by setters/getters.
Throughout your class you will want to use the KVC setters/getters or dot notation to set objects like this
// Dot notation
NSMutableArray *tmpApprovalValues = [[NSMutableArray alloc] init];
self.approvalValues = tmpApprovalValues;
[tmpApprovalValues release]; tmpApprovalValues = nil;
// Call to setters/getters
NSMutableArray *tmpApprovalValues = [[NSMutableArray alloc] init];
[self setApprovalValues:tmpApprovalValues];
[tmpApprovalValues release]; tmpApprovalValues = nil;
Corrected terminology thanks to #Yuji
Related
I have a variable declared like this:
#property (nonatomic, retain) NSMutableArray *aInfo;
At the beggining, if I declare the variable like this:
self.aInfo = [[NSMutableArray alloc] init];
In every point of the app, I can stop the execution with a break point and print the variable content like this:
po self.aInfo
BUT, if I declared the variable with autorelease (as it should be), I cannot see the content anymore in my breakpoint...
self.aInfo = [[[NSMutableArray alloc] init] autorelease];
PD: If I do something like NSLog(#"%#", self.aInfo) I can see the content...
if I declared the variable with autorelease (as it should be)...
As it shouldn't be. Try this:
NSMutableArray *aNewArray = [[NSMutableArray alloc] init];
self.aInfo = aNewArray;
[aNewArray release];
Or use a convenience method, which is in the autorelease pool and which you do not own, so it can be assigned directly:
self.aInfo = [NSMutableArray array];
or:
self.aInfo = [NSMutableArray arrayWithCapacity:20]; // use whatever number makes sense
Remember that when you set up your property to "retain," it does just that. Its synthesized accessors will release the old assignment and retain the new one. So if you assign an alloc'd instance to it directly, that instance will be retained twice, creating a memory leak.*
*Edit: See deanWombourne's comments below. alloc] init] autorelease as a direct assignment to a retained property will not create a memory leak. But I remain unconvinced that it is memory-efficient.
In my iOS app, I am using a NSMutableArray, named imageMArray. I have set its getter and setter properties and instantiated it.
In viewDidLoad:
imageMArray=[[NSMutableArray alloc] initWithArray:CategoryImages];
imageMArray=[self shuffleOnlyArray:imageMArray];
In ShuffleOnlyArray Method:
NSMutableArray *destArray1 = [[NSMutableArray alloc] initWithCapacity: [sourceArray count]] ;
return destArray1;
In shuffle Method:
imageMArray=[[self shuffleOnlyArray:imageMArray] retain];
There appears to be a memory leak in the Shuffle method.
Should I release imageMArray or set it to nil? If it should be released, should it be autoreleased?
imageMArray=[[NSMutableArray alloc] initWithArray:CategoryImages];
In the above statement, you have a memoryleak.
Instead you can have like as follows.
imageMArray = [NSMutableArray arrayWithArray:CategoryImages];
In ShuffleOnlyArray Method, return the autoreleased object.
NSMutableArray *destArray1 = [[NSMutableArray alloc] initWithCapacity: [sourceArray count]] ;
return [destArray1 autorelease];
But after you get it, retain (take the ownership) the array object.
imageMArray=[[self shuffleOnlyArray:imageMArray] retain];
Edit
In shuffle method, do as follows:
NSMutableArray *imageMArray1 = [imageMArray mutableCopy];
if( imageMArray )
{
[imageMArray release];
}
imageMArray=[[self shuffleOnlyArray:imageMArray1] retain];
[imageMArray1 release];
Edit 2:
One more solution:
Use the category to shuffle as mentioned in the SO link
No need of creating new and releasing the arrays.
1 You already have a memory leak in the following lines.
imageMArray = [[NSMutableArray alloc] initWithArray:CategoryImages];
imageMArray = [self shuffleOnlyArray:imageMArray];
In the first line you create an object with retain count 1.
Then you say that your imageMArray pointer points to other object. You should release the first object, because you louse the reference to the fist object and you can not release it after you change the reference!
2 You should not use retain because your ShuffleOnlyArray method returns a retained object.
Your factory method should return an autorelease object and the caller of the factory should decide if if will retain it or not.
Hope I was clear enough
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Use autorelease when setting a retain property using dot syntax?
What is difference between using ivars and self. notation?
instanceVar is instance variable declared with retain.
1) instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"]; //do I need autorelease here?????
2) self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"] autorelease];
Also, Do I need autorelease in the first situation?
This is explained in multiple places but seems as you asked what the different is
The first call is unchanged and looks like this:
instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"];
The second call when compiled will look something like this (assuming you have used a #property with retain and #synthesize:
self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"];
// The previous line will compile to this next line
[self setInstanceVar:[[NSMutableArray alloc] initWithObjects:#"1", #"2"]];
The body of the - (void)setInstanceVar:(NSMutableArray *)instanceVar; method will look something like this (the compiler create this for you because of your #property and #sythesize):
- (void)setInstanceVar:(NSMutableArray *)anInstanceVar
{
if (instanceVar != anInstanceVar) {
[instanceVar release];
instanceVar = [anInstanceVar retain];
}
}
Therefore in the call
self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"];
You have the +1 retain count on the newly created NSMutableArray and then you have the +1 retain count added from going through the setter.
This means that you require the extra release to match retains you are taking. It is considered better to not use autorelease in iPhone so you can be sure memory is being freed when you want it to. Therefore you should normally take the pattern
Create local var
Assign local var to ivar through setter
release local var
Which looks like this (FIXED thanks to #jamapag)
NSArray *tmpMyArray - [[NSArray alloc] initWithObject:#"Hello"];
self.myArray = tmpMyArray;
[tmpMyArray release]; tmpMyArray = nil;
1) instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"]; //do I need autorelease here?????
The NSmutableArray is created with a retain count of 1, you need to release your instanceVar in your dealloc() method
2) self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"] autorelease];
Here you are using the setter, and since it is declared with retain it will increase its retain count by 1, the alloc init already increased the retain count by 1, so the total retain count is 2. However the autorelease msg will decrease this by 1 probaby in the next run loop. So again you only have to release this on your dealloc() method.
In the first situation you probably DO NOT want to autorelease, since this is an IVar you will probably want to use it again, and if you autorelease it the retain count will be 0 soon (most likely in the next run loop)
Hey all. I know this question's been asked but I still don't have a clear picture of memory management in Objective-C. I feel like I have a pretty good grasp of it, but I'd still like some correct answers for the following code. I have a series of examples that I'd love for someone(s) to clarify.
Setting a value for an instance variable:
Say I have an NSMutableArray variable. In my class, when I initialize it, do I need to call a retain on it?
Do I do
fooArray = [[[NSMutableArray alloc] init] retain];
or
fooArray = [[NSMutableArray alloc] init];
Does doing [[NSMutableArray alloc] init] already set the retain count to 1, so I wouldn't need to call retain on it? On the other hand, if I called a method that I know returns an autoreleased object, I would for sure have to call retain on it, right? Like so:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
Properties:
I ask about the retain because I'm a bit confused about how #property's automatic setter works.
If I had set fooArray to be a #property with retain set, Objective-C will automatically create the following setter, right?
- (void)setFooArray:(NSMutableArray *)anArray {
[fooArray release];
fooArray = [anArray retain];
}
So, if I had code like this: self.fooArray = [[NSMutableArray alloc] init]; (which I believe is valid code), Objective-C creates a setter method that calls retain on the value assigned to fooArray. In this case, will the retain count actually be 2?
Correct way of setting a value of a property:
I know there are questions on this and (possibly) debates, but which is the right way to set a #property?
This?
self.fooArray = [[NSMutableArray alloc] init];
Or this?
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
I'd love to get some clarification on these examples. Thanks!
According to Apple's Object Ownership Policy, any method that begins with the words alloc or new, or contains copy is owned by the caller.
To obtain ownership of an object, you must retain it.
So, in your first example, the retain is unnecessary because you already own the object.
The correct way to do this:
fooArray = [[NSMutableArray alloc] init];
Since autoreleased objects are owned by the current autorelease pool, you must call retain on them to gain ownership of them, so this example is correct:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
This would work fine as well:
self.fooString = [NSString stringWithFormat:#"%d items", someInt]; //retained by property setter
And for your last example using the property setter, this would be the correct way to do it:
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
Instead of having to do the above, I'd suggest the following solution:
self.fooArray = [NSMutableArray arrayWithCapacity:10];
arrayWithCapacity: will return an autoreleased NSMutableArray, which is the retain-ed by the property setter method. :)
Ideally you would want to use the accessors whenever possible, especially when dealing with objects as they help avoid many memory issues. So even for instance variables, you should do:
self.fooArray = ...;
instead of
fooArray = ...;
The reason why you should declare properties for object instance variables is because the memory management is slightly more complicated, and recreating it by hand each time is tricky. The correct setter for a nonatomic, retained property would look like:
- (void)setFoo:(NSArray *)aFoo {
if (foo == aFoo) {
return;
}
NSArray *oldFoo = foo;
foo = [aFoo retain];
[oldFoo release];
}
You are right about the instance variable having a retain count of 2 when you do something like this (assuming foo is retained):
self.foo = [[NSMutableArray alloc] init];
The first retain count is coming from alloc, and the second one from your synthesized setter. Any of these should work:
// longer, explicit version, releases immediately (more efficient)
NSMutableArray *aFoo = [[NSMutableArray alloc] init];
self.foo = aFoo;
[aFoo release];
// autoreleased, not so bad unless you're a memory management freak
self.foo = [[[NSMutableArray alloc] init] autorelease];
// an even shorter version of the above
self.foo = [NSMutableArray array];
To create private properties, you can declare them as a class extension in the .m implementation file. To give an example, consider a simple Person object, which has a name, and a boolean property didSave which simply indicates whether the object has been saved to some database or not. Since we don't want to expose this to the outside world, but still keep the benefits of properties inside the implementation file, we can create the header file will all instance variables (public, private, protected) and only public properties:
// Person.h
#interface Person {
NSString *name;
#private
BOOL didSave;
}
#property (nonatomic, retain) NSString *name;
#end
But declare private properties inside the implementation:
// Person.m
// property is declared as a class extension, making it
// invisible to the outside world.
#interface Person ()
#property BOOL didSave;
#end
#implementation
// synthesize as normal
#synthesize name, didSave;
#end
First of all, with this line:
fooArray = [[NSMutableArray alloc] init];
fooArray will automatically have a retain count of 1.
Second, yes, it's 2. And your guess on the setter implementation is correct.
Third, the latter one is right
I have a question about reference counting.
This is my constructor:
- (id)initWithId:(NSString *)graphId;
In another class I make an object in the following way:
GraphViewController *graph =
[[GraphViewController alloc] initWithId:[[NSString alloc] initWithFormat:#"%s", current_ID];
My question is: how do I correctly release the string object?
Is it correct to release the string passed as a parameter?
Any of these ways will work:
(1)
GraphViewController *graph = [[GraphViewController alloc] initWithId:
[[[NSString alloc] initWithFormat:#"%s", current_ID] autorelease]];
(2)
GraphViewController *graph = [[GraphViewController alloc] initWithId:
[NSString stringWithFormat:#"%s", current_ID]];
(3)
NSString *aString = [[NSString alloc] initWithFormat:#"%s", current_ID];
GraphViewController *graph = [[GraphViewController alloc] initWithId: aString];
[aString release];
And, of course, graph needs to be released or autoreleased somewhere.
Never pass ownership around. I.e., in your call to initWithId: you create a string. Make sure it's released in the exact same place. Do not hand the ownership over, burdening another function with the task of releasing what you created (or retained, ...).
If you're not calling initWithId: an unusually high number of times per second, do an autorelease. Even better, use a convenience function. Do not let people talk you into "avoiding the autorelease pool". Because a) it's not so easy to avoid and b) you have more important things to worry about.
In code:
NSString* graphID = [NSString stringWithFormat: #"%s", current_ID];
GraphViewController* graph = [[[GraphViewController alloc] initWithId: graphID] autorelease];
In the constructor, you will simply retain the ID and in the dealloc you will release it again. And please... use (private) #property declarations for this. You can then completely remove the ivar "graphID" from your public interface (if it's private, of course).
#interface GraphViewController ()
#property (copy, nonatomic) NSString* graphID; // copy instead of retain for potentially mutable objects
#end
Then, in initializer and dealloc, boilerplate stuff like:
#synthesize graphID;
- (id)initWithId:(NSString*) ID;
{
self = [super init];
self.graphID = ID;
return self;
}
- (void) dealloc
{
self.graphID = nil; // controversial, Apple policy is [graphID release]; graphID = nil;
[super dealloc];
}
Using this style will make you sleep better at night. Delighted users will raise statues in your name.