How do I fix a memory leak? - objective-c

After doing a long profile test, I found that in one of my ".m" file memory leak occurs in the viewdidload section. i checked and the xcode highlighted the part where i have initialized picker arrays with values. my program uses pickers for user input. and i have 3 5 different views in my program. the first is a disclaimer ,the second is a menu where the user can choose the type of calculation he/she wants to do. each calculation requires certain inputs which the user enters from a picker. for eg. one of the view has 5 inputs which are handled by 5 different uipickers with seperate arrays for holding the values. these arrays are initialized with the values in the viewdidload method of that view. here is what i found after running the test:
...................................................................................................
This is my first time developing an app and i'm kinda confused about what to do. Any help would be appreciated.

Objects in objective c have a retain count. If this retain count is greater that 0 when the object goes out of scope (when you stop using it), it leaks.
The following things increase the retain count
[[alloc] init]
new
copy
[retain]
adding an object to an array
adding an object as a child (e.g. views)
There are likely more, but you don't appear to use any others in your code
The following decrease the retain count
[release]
removing an object from an array
if you dealloc an array, all of its objects are released
You should go through your code and ensure each of the retains or additions to an array are matched with a corresponding release. (You can release member variables in the dealloc method).
EDIT: Jeremy made a valid point that my answer doesn't
Once you add an object to an array, it takes ownership and will release the object when it is done with it. All you need to do is make sure you release anything you own according to the memory management rules
There are also autorelease objects, have a look at this example;
-(init){
...
stagePickerArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 3; i++)
{
//this string is autoreleased, you don't have call release on it.
//methods with the format [CLASS CLASSwithsomething] tend to be autorelease
NSString *s = [NSString stringWithFormat:#"%d", i);
[stagePickerArray addObject:s];
}
...
}
I think the only thing you are missing is a call to release in your dealloc method
-(void) dealloc
{
[stagepickerarray release]; //Do this for each of your arrays
[super dealloc];
}

The leaks tool will only tell you where yo allocated the objects that it thinks leaks. So, it's telling you, for instance, that
NSString* answer = [NSString stringWithFormat: ...
allocates an object that is never deallocated. Now, -stringWithFormat: gives you an object that you do not own and you don't seem to retain it anywhere. Therefore, you do not need to release it, so it can't be leaking by itself.
That means something else that you do own must be retaining it and you never release that something else. The prime suspect would appear to be stagePickerArray. Check that you are releasing stagePickerArray somewhere. If it's local to -viewDidLoad it must be released or autoreleased before the end of that method. If it's an instance variable, it must be released in the class's -dealloc method.

In Objective-C you need to take care of the retain count of allocated memory. If you don't need it -> release it.
Whenever you alloc an object, it will return an object with retain count = 1.
By using retain, the retain count gets incremented,
by using release, the retain count gets decremented.
Whenever the retain count is equals 0, the object will be destroyed.
So whenever you want to use the object somewhere else you need to retain it. So you make sure that the object is not deleted after the other 'person' (or whatever it used ;)) called release.
This was a very very very short description. Check the following guide
Memory Management Guide for iOS.
(Also you want to read something about ARC - Automatic Retain Counting - which is new in iOS5! ios5 best practice release retain

Related

Objective C memory management example

I'm trying to learn objective c and I'm still a bit confused with memory management.
Yes I know, I should use ARC, but my project uses TouchXML that does not support it.
Also there is a lot of documentation and threads about memory management that I have read but I still have some doubt that I hope you guys will help me to clarify.
I've learnt that who allocs an object is then responsible to free it. I've also learnt that "retain" increments the reference counter whereas "release" decrements it. When an object's reference counter reaches 0, it is automatically de-alloced.
I've finally learnt that "autorelease" releases the object automatically at the end of current event cycle. That's fine.
Now please consider the following case:
I alloc an array that I need to use for the full lifecycle of my object. I'm responsible to release it when my object is deleted:
#implementation MyClass
-(id) init {
myArray = [[NSMutableArray alloc] init]; // this is a #property
}
- (void) dealloc {
[myArray release];
[super dealloc];
}
#end
In this way, in dealloc method, myArray release also causes myArray o be deallocated.
If I then instance a new object from myClass and retain myArray like this...
// MyOtherClass
MyClass *o = [[[MyClass alloc] init] autorelease];
NSMutableArray *retainedArray = [[o.myArray] retain];
...at the end of current event cycle, "o" will be automatically deallocated, whereas retainedArray (actually pointing to o.myArray) will not be deallocated until I'll call [retainedArray release].
Is this correct up to here?
If so, I also guess the same applies if I call something like:
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:#"somePath" error:nil];
I don't need (actually I can't otherwise it will give a runtime error) call either release or autorelease for "contents" unless I retain it somewhere in my code. Correct?
If so, summing everything up, in the end I only have to call release if I call either alloc or retain. The balance of reference counts in my class should always be 0, where alloc / retains gives +1 and release gives -1. Correct?
It is almost 100% correct what you said, but there are a few more cases where you get
a (+1) retained object that you have to release.
The basic rules are (see "Basic Memory Management Rules"):
You must eventually release or autorelease objects that you own.
You own objects that you created using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”
You own an object if you take the ownership using retain.
The "Static Analyzer" (Product -> Analyze in the Xcode menu) is quite good at finding
violations to this rule, so I can only recommend to use that.
You can use Touch XML with ARC just fine. I use TouchXML in my project also. Just go to project build phases, double click on each Touch XML.m file, and enter -fno-objc-arc. This will disable ARC for that file.
If you know a lot about memory management or really want to learn more about memory management, then use MRC, but if you want to avoid the hassle, use ARC.
no direct answer to your question, but you also can use non-ARC Code in an ARC Project:
http://www.codeography.com/2011/10/10/making-arc-and-non-arc-play-nice.html
Best regards
Bernhard

How to add alive object to NSMutableArray and remove them when they're released?

I have class Item and class List (which has an NSMutableArray).
Every time class Item is instantiated (and destroyed) it posts a notification, which is listened-to by class List. When class List receives the notification is adds the instance of class Item to its list.
I'm trying to have class Item also post a notification that its about to be dealloc'd. The problem is that class List's NSMutableArray retains the instance of class Item.
What's the most appropriate means of handling this situation? If I decrement the count when adding it to List's array, then an exception will be thrown when class List attempts to call removeObject (since it'll try to dealloc the object.)
Basically, I want a "monitor" class List that contains a list of all "live" instances of Item. But, I also need the ability to release/dealloc the instances and have them report they're being dealloc'd so List can remove them from its NSMutableArray.
Thanks for your help.
If I understand correctly, you want an array that maintains weak references to its items, as opposed to strong references?
I don't know of a way to do this with anything "built-in" in Cocoa. The only way I'd know of to do this is to make the array yourself, and have the storage be __weak id[]. That would automatically zero-out the place in the array when the object deallocates. If you're under the retain-release model, you could use something like MAZeroingWeakRef to get the same behavior.
This is definitely an interesting question, and I don't know of an easier answer. I'd love to be proven wrong!
Ha, I love being wrong!
There's a class called NSPointerArray that looks like it can do what you're looking for. However, it's only available on the Mac, and it only auto-zeros when you're using garbage collection.
I'll keep thinking about this. This is an interesting problem! :)
So I kept thinking about this, and came up with a solution. It uses two unconventional things:
A subclass of NSMutableArray (egads!)
Using an associated object to determine object deallocation
For the first bit, I had to to subclass NSMutableArray so that I could inject some custom logic into addObject: (and related methods). I didn't want to do this via swizzling, since NSArray and friends are a class cluster, and swizzling into/out of clusters is fraught with peril. So, a subclass. This is fine, but we're going to lose some of the awesome features we get from "pure" NSArray instances, like how they do weird things when they get big. Oh well, such is life.
As for the second bit, I needed a way for any arbitrary object to notify that it is about to or just finished deallocating. I thought of dynamically subclassing the object's class, injecting my own dealloc/finalize method, calling super, and then smashing the isa of the object, but that just seemed a little too crazy.
So, I decided to take advantage of a fun little thing called associated objects. These are to ivars what categories are to classes: they allow you to dynamically add and remove pseudo-instance variables at runtime. They also have the awesome side effect of getting automatically cleaned up with the object deallocates. So what I did is just created a little throw away object that posts a notification when it is deallocated, and then attached it to the regular object. That way when the regular object is deallocated, the throw away object will be as well, resulting in a notification being posted, which I then listen for in the NSMutableArray subclass. The notification contains a (stale) pointer to the object that is in the process of getting destroyed, but since I only care about the pointer and not the object, that's OK.
The upshot of all of this is that you can do:
DDAutozeroingArray *array = [DDAutozeroingArray array];
NSObject *o = [[NSObject alloc] init];
[array addObject:o];
NSLog(#"%ld", [array count]); //logs "1"
[o release];
NSLog(#"%ld", [array count]); //logs "0"
The source is on github, and it should (theoretically) work just as well on iOS as Mac OS X (regardless of GC mode): https://github.com/davedelong/Demos
Cheers!
... and I just thought of a way to do this without a custom subclass, but I'm tired and will post the updated answer tomorrow.
the next morning...
I've just updated the project on Github with an NSMutableArray category that allows you to create a true NSMutableArray that auto-zeroes its objects as they're deallocated. The trick was to create a CFMutableArrayRef with a custom retain callback that sets up the proper observation, and then just cast that CFMutableArrayRef to an NSMutableArray and use that (ah, the magic of Toll-Free Bridging).
This means you can now do:
NSMutableArray *array = [NSMutableArray autozeroingArray];
I added a typedef to define these as NSAutozeroingMutableArray, just to make it explicitly clear that while this is an NSMutableArray, it doesn't retain its objects like a normal NSMutableArray. However, since it's just a typedef and not a subclass, you can use them interchangeably.
I haven’t tested this, so comments are welcome.
You could use an NSPointerArray for the list (in a retain property):
self.array = [NSPointerArray pointerArrayWithWeakObjects];
When an Item object is created, it would post a notification that’s listened by your List class. Upon receiving the notification, List adds the object to the pointer array:
[array addPointer:pointerToTheObject];
In this setting, the pointer array doesn’t keep a strong reference to its elements — in particular, it doesn’t retain them. This applies to both garbage-collected and non-garbage-collected builds.
In a garbage-collected build, if an element is garbage collected then the garbage collector automatically assigns NULL to the position in the array where the object was stored.
In a non-garbage-collected build, you’ll need to manually remove the element or assign NULL to the position in the array where it was stored. You can do this by overriding -[Item dealloc] and posting a notification that the object is being deallocated. Your List class, upon receiving the notification, would act upon it.
Note that, since objects are not owned by the pointer array, you must keep a strong reference to (or retain) them if you want to keep them alive.

Allocating and releasing memory in iPhone Xcode 3.2.5, iOS 4.2.1

I am having a strange issue with tableview showing (null) when another ViewController comes and goes. I traced it down to the place that it reads the data to display to the tableview and found that it read null for data. To debug this, I need to understand how memory management really works for iPhone. I used the following code in my application delegate to create an array of objects. This was from a sample code which I modified for my app. My question is when one creates an array like this, would the [tempArray release] actually release the array that was just created?
//Initialize the hardware array.
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.hardwareArray = tempArray;
[tempArray release];
This type of code seems to be very common for iPhone. The tutorials keeps saying for example, now that you passed the data to the controller you can release it. But my C and C++ experience tells me, if you release the memory it would be gone, and if its address is sitting someplace on the stack, its no good. Is the data being copied to another place rather than address being passed?
Also when releasing memory in a set routine like the one below, should I be checking to see if the modleName is not nil before releasing it. What happens if one released modelName that is already nil?
-(void) setModelName:(NSString *)newValue {
self.isDirty = YES;
[modelName release];
modelName = [newValue copy];
}
My question is when one creates an array like this, would the [tempArray release] actually release the array that was just created?
If the #property of the object is assign it would get released. But usually you use retain or copy as #property. And if the property is retain, the setter you call with self.hardwareArray = ... (ie [self setHardwareArray:...]) will retain the object. If the property is copy it will create a new object that is retained already.
Also when releasing memory in a set routine like the one below, should I be checking to see if the modleName is not nil before releasing it. What happens is one released modelName that is already nil?
In objective-c messages sent to nil are perfectly legal. No need to worry, no need to check for nil.
If you release an instance variable outside of dealloc you should set it to nil after releasing it.
release doesn't do what you think - it isn't equivalent to free() or delete and doesn't cause the memory to be gone.
It really is important to fully understand the few simple memory management rules before you do any coding. It's not difficult, the best resources are the Apple Developer Guides, like this one
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html%23//apple_ref/doc/uid/10000011i

EXC_BAD_ACCESS for NSMutableArray

I have a NSMutableArray with a few view elements.
I remove the view from the view hierarchy and then check the retain count of the array, it returns 1. I then send [array release] but the code dumps with EXC_BAD_ACCESS.
I see that there are elements in the array but still the code dumps.
Here is what I found during debugging. The array has all the 100 objects present (count on the array returns 100) and the contents when seen on a debugger returns "Out of Scope" for the elements. Also, since the array is in the view hierarchy, the following code reduces the retain count by two:
for (Liv *view1 in viewArray){
NSLog(#"view count = %d", [view1 retainCount]);
[view1 removeFromSuperview];
NSLog(#"view count = %d", [view1 retainCount]);
}
Do not use retainCount
It is useless for this kind of debugging; you are working with views in the framework's view hierarchy. There could be any number of reasons why the retain count goes up or down by 2, 10, or 42.
From the roundabout evidence posted so far, this appears to be a very straightforward memory management issue.
First, use "build and analyze" to have the llvm static analyzer check your code. Fix any problems it identifies.
Next, how is the array allocated? Where do you store it? Post all of the lines of code that declare or manipulate the array.
Finally, as Paul said, turn on zombies and see what happens.
There is an off chance that this isn't a retain/release issue, but there isn't any evidence to indicate that yet.
Did you retain or alloc the array? If not, you shouldn't be sending it a release.
EXC_BAD_ACCESS means you're sending a message to a object that's already been released. You (or some code somewhere) is releasing it prior to the part of your code where you're sending release (or removeAllObjects).
Basically, if your retains and releases are balanced, you won't get this error. We'll need to see some code before we can offer anything more than generic advice.
Using NSLog() and retainCount isn't the easiest way to debug errors of this nature. Assuming you're on Xcode 3.2.6, then try running your code via Run > Run with Performance Tool > Zombies. That should give you a good pointer as to which part of your code is faulty.

What does 'release' means in this situation on iPhone?

I want to ask a stupid question about the iPhone application. I am the green of the iPhone app. I read the following code in the Apple website.
MyViewController *aViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
[self setMyViewController:aViewController];
[aViewController release];
And I have a question, how it means of the 'release' in the line 3?
Does it presents the memory clear? or the program take control of that object? or other meanings. Thank you very much.
When you alloc something, the object you get will have a retain count of 1 - this means that this object is currently being used by someone, so it should not be removed from memory. If you call retain on an object it will increase the retain count, meaning the object is being used by 2 things. If the retain count reaches 0, it implies that the object is no longer being used by anything and it can be removed from memory. You can decrease an object's retain count by calling release on the object.
In your example, aViewController is alloc'd and after line 1 has a retain count of +1.
It is then set as the view controller in line 2. This method is therefor taking ownership of the object, so should retain it for its own use.
Line 3, we don't want anything more to do with the view controller, so we release our hold of it. The retain count decreases by one - and it is now up to the new owner to release it when it is finished with it.
You might find it helpful to read through the memory management section of this tutrial
Whenever you call alloc, you own a reference to the object that comes back, and you must call release to indicate that you no longer intend to use that reference.
In the above case, you have allocated a new view controller and assigned it to a property of your class. Assuming the property is declared with the retain option, the property will acquire its own reference to the view controller by called retain on it. So there are now two active references to it. The property will eventually release its reference (either when it is assigned a different view controller, or when your class is finalised). But if you don't call release yourself, one reference will remain, and the view controller will never be freed.
In short, you must match every alloc with a release, otherwise things will leak.