Dealloc objects of another class - iphone

Hi I generally create objects of another classes. can you please tel me if this wil be in the auto release pool? or should we release it manually.

if you init copy or new them you'll have to deallocate them if you put an autorlease with the allocation then they will be autoreleased
for example
Foo *foo = [[Foo alloc] init]; //you'll have release it somewhere yourself
And
Foo *foo = [[[Foo alloc] init] autorelease];// this will be autreleased

The simple case is : if you use init, you are responsible for releasing it, either by calling release or by calling autorelease.
e.g.
NSString *myString = [NSString alloc] init]; // You need to release this
...
[myString release]; // Now it's released - don't use it again!
or if you are going give it to someone else
NSString *myString = [NSString alloc] init]; // This needs releasing
...
return [myString autorelease]; // You are finished with it but someone else might want it
However, there's a few other cases.
NSString *myString = [NSString stringWithFormat:#"hi"];
This object is in the autorelease pool already - don't release it!
NSString *secondString = [myString copy];
This object needs releasing - it is not autoreleased.
Rule of thumb : Anything with init, copy or new in the name - you made it, you release it. Anything else will be autoreleased.

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

Memory leak when using NSString inside for loop

I have 100 images in my resource bundle named like image1.jpg,image2.jpg.
Basically what i am trying to do is create path names to those images dynamically inside a for loop.
While testing in simulator,the images loaded fine and the app did not crash.But while testing the app with instruments i was shocked to see the heavy memory leak that was happening while i was creating the path1 object.
I am pasting the entire method here for reference
- (id)init {
self = [super init];
if (self) {
self.arrayImages = [[[NSMutableArray alloc] init] autorelease];
for(int i=1 ; i<100 ; i++){
NSString *str = [NSString stringWithFormat:#"Century%d",i];
NSString *path1 = [[NSBundle mainBundle] pathForResource:str ofType:#"jpg"];
[self.arrayImages addObject:path1];
}
}
return self;
}
As i have not made use of any alloc inside the loop i dont have any ownership and hence no right to release the object.What is the reason for this memory leak??
Kindly explain the problem and provide the necessary solution in order to fix it..
As always,any help is highly appreciated..
arrayImages is retaining path1, and so if you do not release arrayImages it will leak. How are you creating arrayImages, and are you releasing it anywhere?
Edited based on comments:
Make sure you release arrayImages in your -dealloc method like so: [arrayImages release]; (note the lack of self).
There is no leak in the code you've shown.
There are (at least) two possibilities:
You have a leak in code you didn't paste into your question
Everything is fine and Instruments gave you a false-positive
Your loop will create a lot of autoreleased variables. These won't be deallocated until after the loop has finished, but that's how it's supposed to work.
The reason for the leak would be this line right here:
NSString *str = [NSString stringWithFormat:#"Century%d",i];
By using convenience methods in Objective-C, what happens in the background is the following:
NSString *str = [[[NSString alloc] initWithFormat:#"Century%d", i] autorelease];
Not using alloc/init to create a weak reference is a misconception. You are always the owner of a created object, no matter how you create it. The convenience method simply does the alloc/init and autoreleases it for you.
Here's what I would suggest you do to avoid leaking memory:
- (id)init {
self = [super init];
if (self) {
self.arrayImages = [[[NSMutableArray alloc] init] autorelease];
NSAutoreleasePool *tmpPool = [[NSAutoreleasePool alloc] init];
for(int i = 1 ; i < 100 ; i++) {
NSString *str = [NSString stringWithFormat:#"Century%d",i];
NSString *path1 = [[NSString alloc] initWithString:[[NSBundle mainBundle] pathForResource:str ofType:#"jpg"]];
[self.arrayImages addObject:path1];
[path1 release];
}
[tmpPool drain];
}
return self;
}
Let me know if this works better for you.
-EDIT- Allocating the path1 object and releasing it after adding to arrayImages.

Potential memory leak

I work on a project on iPhone iOS with Xcode 4.
With Xcode > Product >Analyze I get 35 issues, all of this type:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
and the problem is "Potential leak of an object allocated at ..."
What is the offending object and how can I release it?
Thanks
You're leaking the string that you're assigning to myTextField.text. When this assignment happens, a copy is being made (look at the property definition in the documentation). In most cases, when values are immutable, as is the case with NSStrings, a copy will give you an instance that points to the same location as the object that is being copied, with the retain count incremented by 1.
In the case of your code:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
The retain count of the string that you've allocated is 2.
You will either need to (1) release, (or autorelease) the string, or (2) use one of the NSString convenience methods, e.g. stringWithFormat: to create the string. This will give you an autoreleased string so you won't have to worry about explicitly releasing it.
(1)
NSString *str = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = str;
[str release]
or
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
(2)
myTextField.text = [NSString stringWithFormat:#"0.2f", abc]; // autoreleased
You are responsible for releasing string object you create here - as you use alloc/init for that.
The most convenient way here to set a string is to use class method +stringWithFormat that returns autoreleased string - so system will release that string object for you later:
myTextField.text = [NSString stringWithFormat:#"0.2f", abc];
Or you can write autorelease explicitly if you want:
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
If you don't want to use autorelease you can use temporary variable to create new string and release it after it was set for text field:
NSString *tempString = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = tempString;
[tempString release];
The thing is that UiTextFields's text property is declared as:
#property(nonatomic, copy) NSString *text
Therefore in this line:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
A new NSString is created with a retain count of 1, and then myTextField.text copies this object and increased its retain count by 1 or does it??, lets see what is happening:
A NSString object created with alloc initWithFormat with a retain count of 1
A NSString object with is a copy of the previous String, but because NStrings are immutable in this case, copy returns the same object!, therefore the NSString actually has a retain count of 2.

Memory leaks Problem in iPhone?

I want to get some memory leaks in my code, how can i fix the memory leak.
dashboard = [[NSMutableArray alloc] init];
[dashboard addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil]; // memory leaks here.
if ( theConnection ) {
receiveData = [[NSMutableData data] retain]; //memory leaks here.
}
But i have released dealloc - in[receiveData release];, but memory leaks happened. I know the retain, the count is increased, but how can i released the data properly.
Thanks!
i think your leak in the line:
[dashboard addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil];
just change it to
[dashboard addObject:[NSDictionary dictionaryWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil];
addObject retains the object so you can use convenience creation methods which autorelease the object they create.
and another possible leak... if you define your receiveData as a property with retain attribute you don't need to call retain explicitely. You can call self.recieveData = [NSMutableData data]. This will retain it. Of course you will still need to release it in dealloc.
EDIT to show the code:
NSMutableArray *anArray = [[[NSMutableArray alloc] init] autorelease];
[sections setValue:anArray forKey:display_date];
dashboard addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil];
You've called init method - then you are the owner of an object. When you've put it to the array - the retain was called too. Just call autorelease to fix the leak.
receiveData = [[NSMutableData data] retain]; - if you will call release this object will be deleted when out of scope. If you will write
receiveData = [NSMutableData data];
It will be automatically deleted when out of scope
EDIT
If you are using methods with init word in them then you are the owner of such objects and they will not be deleted automatically until you'll call release method on them. If you don't want to own the object create it with some static method. For example:
NSMutableArray *array = [NSMutableArray arrayWithObjects: ... , nil];
It's the same as calling
NSMutableArray *array = [[[NSMutableArray alloc] initWithObjects: ... , nil] autorelease];
Autorelease means the object will receive a release method when out of scope - and if it was not retained will be deleted automatically

Memory Management in Objective C

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.