Memory Management in Objective C - iphone

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.

Related

MutableCopy AllocLeak MemoryLeak

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];

do I need to allocate and init variables with retain properties?(iphone)

#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

iPhone memory management (with specific examples/questions)

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

Objective C: retain vs alloc

I have a singleton class with this code:
manager.h
#interface Manager : NSObject {
NSString *jobsLimit;
NSMutableDictionary *jobTitles;
}
#property (nonatomic, retain) NSString *jobsLimit;
#property (nonatomic, assign) NSMutableDictionary *jobTitles;
#implementation Manager
#synthesize jobsLimit;
#synthesize jobTitles;
+ (id)sharedManager {
#synchronized(self) {
if(shared == nil)
shared = [[super allocWithZone:NULL] init];
}
return shared;
}
- (id)init {
if (self = [super init]) {
jobsLimit = [[NSString alloc] initWithString:#"50"];
jobTitles = [[NSMutableDictionary alloc] init];
}
return self;
}
Then in the code i'm assigning these variables like this:
self.jobsLimit = [NSString stringWithFormat:#"%d", progressAsInt];
[self.jobTitles addEntriesFromDictionary:anotherDictionary];
- (void)dealloc {
[super dealloc];
[jobsLimit release];
[jobTitles release];
}
Now my question is this code correct? Is the assignment correct?
I'm very confused with when to use alloc and/or retain. Do I need to use alloc if my property is already retained? and If I use alloc should my property be assign?
What will be the reference count now for these variables and will they be dealloc'd/under-dealloc'd when the dealloc is called?
Also for singleton classes do I need to initialize my ivars as in the init method above or I do not have to.
I'd appreciate if someone can help me clear this confusion out and thanks in advance.
Regards,
Your code actually looks correct, but perhaps some explanation is in order, since it sounds like you're a little unsure.
When you assign to a property that has retain semantics using the "." syntax, the accessor method calls retain. The "." syntax is just shorthand for invoking the accessor method, so
self.jobsLimit = [NSString stringWithFormat:#"%d", progressAsInt];
is exactly the same as
[self setJobsLimit:[NSString stringWithFormat:#"%d", progressAsInt]];
That works out to:
create an (autoreleased) string with a numeric value
retain the string (you now own it) and assign it to jobsLimit
If, on the other hand, you assign to the iVar directly (not using the "."-accessor), the setter method is not called. For example:
jobsLimit = [[NSString alloc] initWithString:#"50"];
That is:
allocate a string (you own it), with value "50"
assign it to jobsLimit
Either way, you now own the string referred to by jobsLimit, and are responsible for eventually releasing it (e.g., in your dealloc method).
I guess you need a lot of this : IOS Memory Management
and a bit of : What should my Objective-C singleton look like?
good lectures !

releasing and retaining NSString* properly

Hi all i'm still new to iPhone development, but had strong experience with other programming languages. The thing that makes me pull my hair out is the Obj-C memmory management and releasing / retaining properly. I know the concept, i know "once i understand it will be easy" but i'm not quite still there, and that makes me crazy. Here i have one simple piece of code with class and method, that simply add's one character to existing string that is synthesized so used as class proprety ... the class for example is called myClass ...
myClas.h
#interface myClass : NSObject {
#private
NSString* someCommonString;
}
#propery (retain, nonatomic) NSString* someCommonString;
myClass.m
...
#synthesize someCommonString;
- (id) init
{
self = [super init];
if(self)
{
someCommonString = [[NSString alloc] initWith String:#"one "];
}
}
- (NSString*) appendString:(NSString*) stringToAdd
{
NSString* result = [someCommonString stringByAppendingString: stringToAdd];
return result;
}
- (void) doTheJob
{
NSString* test1 = #"two ";
NSString* test2 = [[NSString alloc] initWithString: #"three "];
NSString* test3 = [NSString stringWithFormat:#"four "];
self.someCommonString = [self appendString:test1];
self.someCommonString = [self appendString:test2];
self.someCommonString = [self appendString:test3];
NSLog(#"%#", someCommonString);
}
- (void) dealloc
{
[someCommonString release];
[super release];
}
...
Ok, after i alloc myClass and execute the doTheJob method, i should have #"one two three four" in the someCommonString class proprety. I know this is working, but is also leaking as hell. test1, test2 and test3 are 3 ways of initialising NSString, and only the test2 should be released, this is quite self-explanatory, but im much more worried what happens when passing them as arguments to the appendString method. Because there i know i hawe a leak, but don't know how to handle 1. stringToAdd argument [should i worry about it in appendString method at all ?] 2. the result -> if i autorelease the result, i don't know at which point the result will be deallocated. 3. sommeCommonString in appendStringMethod, should i retain it, release it or leave it alone ?
Huh :)
At a first glance, it seems to me like you're not releasing test2. After you have appended it to your common string, you do not need to retain it anymore.
self.someCommonString = [self appendString:test1];
self.someCommonString = [self appendString:test2];
self.someCommonString = [self appendString:test3];
[test2 release];
The other two (test1 and test3) are autoreleased, so your thread will reclaim them at some point).
As far as your appendString: method is concerned, result is already autoreleased and in fact you could reduce your implementation to
return [someCommonString stringByAppendingString: stringToAdd];
someCommonString is not affected by the operation at all. stringByAppendingString: returns a new autoreleased string from the concatenation of self and stringToAdd.
Hope that helps
… but im much more worried what happens when passing them as arguments to the appendString method. Because there i know i hawe a leak, but don't know how to handle
1. stringToAdd argument [should i worry about it in appendString method at all ?] …
You don't have a leak in -appendString:. You are passing stringToAdd around without retaining it and that's okay here.
The result is autoreleased and you don't have to take any action on it.
2. the result -> if i autorelease the result, i don't know at which point the result will be deallocated.
The result is already autoreleased and will be released as soon as the current NSAutoreleasePool will be released. Til then you can pass it around without retaining.
3. sommeCommonString in appendStringMethod, should i retain it, release it or leave it alone ?
Leave it alone, it's managed by the accessors. But as fedmest (and you too) said: release test2.
Well there are few problems in your code, but basic problem is you need NSMutableString string, not NSString to make your code work.
in init method, correct code to initialize is,
someCommonString = [[NSMutableString alloc] initWithString:#"one "];
You have to return the object (self) from init, otherwise it will not work, like this.
return self;
If you wanted to append the string, it should be NSMutableString, not NSString.
[[self someCommonString] appendString:test1];
[[self someCommonString] appendString:test2];
[[self someCommonString] appendString:test3];
In dealloc method, you call dealloc method of super, not release the super. So correct it it like this.
[super dealloc];
There is no need to release test1 and test3, because they are autorelease.
I have witten the correct code, try this out.
#interface myClass : NSObject {
#private
NSMutableString* someCommonString;
}
#property (retain, nonatomic) NSMutableString* someCommonString;
- (void) doTheJob;
#end
#implementation myClass
#synthesize someCommonString;
- (id) init
{
self = [super init];
if(self)
{
someCommonString = [[NSMutableString alloc] initWithString:#"one "];
}
return self;
}
- (NSString*) appendString:(NSString*) stringToAdd
{
NSString* result = [someCommonString stringByAppendingString: stringToAdd];
return result;
}
- (void) doTheJob
{
NSString* test1 = #"two ";
NSString* test2 = [[NSString alloc] initWithString: #"three "];
NSString* test3 = [NSString stringWithFormat:#"four "];
[[self someCommonString] appendString:test1];
[[self someCommonString] appendString:test2];
[[self someCommonString] appendString:test3];
NSLog(#"%#", someCommonString);
[test2 release];
}
- (void) dealloc
{
[someCommonString release];
[super dealloc];
}
#end
This is a technique which might help you deal better with what is happening with the #synthesize directive. Change your header as follows
#interface myClass : NSObject {
#private
NSString* _bob;
}
#property (retain, nonatomic) NSString* someCommonString;
and your class file to
#synthesize someCommonString = _bob;
If you recompile your code you will get build errors. Fix these and you will suddenly be able to see exactly what you are accessing via the synthesized property and what you are directly accessing.
Additionally, as already mentioned, you need to release test2 in the doTheJob method.