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.
Related
I have an NSTimer that fires once per second.
And every second I have an NSString that needs to be changed.
I've never tried to deal with memory management before so I'm not sure if what I'm doing is right but instruments is saying under "alloc" that the line of code with stringByReplacingOccurrencesOfString has 45MB of "Live Bytes" after about a minute...
(and the live byte count keeps on rising with every second and eventually crashes the app).
I think my issue lies somewhere with the MutableCopy code?
Here is my code:
-(void)myTimer {
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
testedit = [[NSString alloc] initWithFormat:#"example"];
withString1a = [[NSString alloc] initWithFormat:#"e"];//this string gets its values randomly from an array in my real code
forString1a = [[NSString alloc] initWithFormat:#"flk34j"];//this string gets its values randomly from an array in my real code
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];//memory leak /:
}
You are allocating memory for each object twice. When you alloc the second time and assign it to the same variable, the first piece of alloc'd memory becomes inaccessible and unreleasable.
Then you make a mutableCopy of testedit and assign the copy to the original's variable. Again, you leave a piece of inaccessible memory floating around.
The rule with non-ARC memory management is - for every alloc, new, copy or retain you need to have a corresponding release. You have 6 allocs, one copy, and only 3 releases.
Here are some suggestions.
Remove these duplicated allocations:
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
Presumably testedit, withString1a and forString1a are all iVars. (Please declare your iVars as autosynthesized properties and refer to them as self.testedit ... etc. that will make your code so much clearer to stack overflowers).
Take out all of this:
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
Assuming these are all iVars, the correct place to release them is in your object's dealloc method
In fact withString1a and forString1a can be local variables, as you get their content from elsewhere:
NSString* withString1a = [[[NSString alloc] initWithFormat:#"e"] autorelease];
NSString* forString1a = [[[NSString alloc] initWithFormat:#"flk34j"] autorelease];
You can autorelease them as you don't need them to hang around after the method has finished.
These lines can also be written:
NSString* withString1a = [NSString stringWithFormat:#"e"];
NSString* forString1a = [NSString stringWithFormat:#"flk34j"];
(-stringWithFormat is a convenience method that returns an autoreleased object)
That leaves us with these two lines.
testedit = [[NSString alloc] initWithFormat:#"example"];
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] mutableCopy];
It's not clear why you are treating testedit as an immutable string in the first line and a mutable string in the second. You don't need a mutable string here at all, as you are replacing testedit with a new string.
self.testedit = [[NSString alloc] initWithFormat:#"example"];
self.testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] copy];
(you need copy as stringByReplacingOccurrencesOfString:withString: returns an autoreleased object, and here you want to keep hold of it)
THE last piece of the jigsaw is getting rid of your _testedit iVar memory allocation. You do this in the dealloc method of your object:
- (void) dealloc {
[_testEdit release];
[super dealloc];
}
(Note that init, accessor, and dealloc methods are the three places where you should not refer to an iVar using property syntax.)
All good, but really, you should be using ARC! You are _far_more likely to introduce memory bugs this way than if you rely on the compiler to manage memory for you.
I would suggest you to make use of #property here.
In .h file declare the properties as:
#property (nonatomic, retain) NSString *testedit;
#property (nonatomic, retain) NSString *withString1a;
#property (nonatomic, retain) NSString *forString1a; //if required write the #synthesize as well in .m class
You can write your timer method as:
-(void)myTimer {
self.testedit = #"example";
self.withString1a = #"e";//this string gets its values randomly from an array in my real code
self.forString1a = #"flk34j";//this string gets its values randomly from an array in my real code
self.testedit = [self.testedit stringByReplacingOccurrencesOfString:self.withString1a withString:self.forString1a];
}
In dealloc method, you can set all the above properties as nil (self.testedit = nil;) or do a release on them([testedit release];).
If possible, try to switch to ARC, you dont have to worry about the memory management. The problem with your code was that you are using a lot of alloc/init statements without releasing the variable before doing it. This causes it to lose the reference of that variable and you will leak it. You dont need that many allocation statements. For every allocation or retain, there should be a corresponding release/auto-release statement.
If you're using ARC you shouldn't have an issue. If you aren't using ARC you can try adding autorelease:
testedit = [[[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy] autorelease];
You are getting a memory leak because you never de-allocate testedit. Whenever you call alloc, that means you need to deallocate it. This usually just means calling release.
Do something like this instead, then be sure to free up the memory you've allocated:
NSString* newString = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];
I have an NSMutableArray with the following property:
#property (nonatomic, strong) NSMutableArray *alarmTableArray;
alarmTableArray = [[NSMutableArray alloc]init];
FMDBDatabaseAccess *db = [[FMDBDatabaseAccess alloc] init];
alarmTableArray = [db getAlarm];
I tried releasing this array but I end up with EXC_BAD_ACCESS.
I am really worried about this.
How to release this array?
You're using the descriptor of "strong" which is an ARC term. This should be retain and if you just set the property to nil it will release it automatically. You should set it to nil in your viewDidUnload since your ViewWillDissappear only means your viewcontroller is leaving visibility and not that it is being destroyed.
Updated Answer
I think I know what you're trying to do. You want grab an array of rows from your SQL and store it in one of your array.
One of the techniques for getting rows of data from SQL and storing into a class instance variable array is to NOT return a temporary array but pass the class instance variable array as a reference into your method and modify the array directly.
So instead of this pseudo-code
-(NSMutableArray *)doSomething
{
NSMutableArray *tempArray;
while (DB select statement has found rows)
{
CockTail *objCT = [[CockTail alloc] init];
objCT.name = #"...";
objCT.price = #"...";
[tempArray addObject:objCT];
[objCT release];
}
return [tempArray autorelease];
}
// class instance variable array
instanceVarArray = [[NSMutableArray alloc] init];
instanceVarArray = [self doSomething]; // here is where you confusion arise
You can do it this way:
-(void)doSomething:(NSMutableArray *)paramArray
{
// remove previously fetched data
[paramArray removeAllObjects];
SQL select statement
while(has rows)
{
CockTail *objCT = [[CockTail alloc] init];
objCT.name = #"...";
objCT.price = #"...";
// NOTE: we are directly modifying our class instance variable array
// here since it was passed by reference :D
// and so there is no need to worry about releasing the array
[paramArray addObject:objCT];
[objCT release];
}
}
// Now all you do is pass in your class instance variable array
instanceVarArray = [[NSMutableArray alloc] init];
[self doSomething:instanceVarArray];
Original Answer
Um, maybe I am wrong but aren't you essentially throwing away that "alloc init" on the first line here when you assign the array something from your FMDBDatabaseAccess:
// LINE 1: this instance of NSMutableArray here is allocated
alarmTableArray = [[NSMutableArray alloc]init];
// LINE 2
FMDBDatabaseAccess *db = [[FMDBDatabaseAccess alloc] init];
// LINE 3:this line here essential breaks the pointer link point to the NSMutableArray instance on line 1
alarmTableArray = [db getAlarm];
Now unless you do
// LINE 4
[alarmTableArray retain];
Otherwise, your alarmTableArray was never allocated (since you overwrote the pointer link). And as a result, you've caused a memory leak as your profiler told you.
Doing a release now would give your that EXEC_BAD_ACCESS
What I think you want to do is this:
alarmTableArray = [[NSMutableArray alloc]init];
FMDBDatabaseAccess *db = [[FMDBDatabaseAccess alloc] init];
// this now uses the setter method (mutator method generated by #property) to do the copy
self.alarmTableArray = [db getAlarm];
Looking at your while loop, I have to ask why are you releasing a local scope variable?
CockTail *cocktailValues = [[CockTail alloc] init];
...
[cocktails addObject:cocktailValues];
[cocktailValues release];
Breakdown of each line of code above:
When you alloc and init the CockTail object the release/retain count is 0.
Adding the object to the NSMutableArray increases the release/retain count to 1.
Releasing the CockTail object after you added it to array reduce the release/retain count back down to 0.
Therefore, later when you release the NSMutableArray or try to access an object in it, the objects are already gone.
Remember the number one rule, only release what you retain.
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)
#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
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