How can I securely free up memory by removing UIImageViews from the screen? - iphone

I have some UIImageViews that are nested in UIViews, which group them together. They're owned by an view controller. As soon as the -viewWillDisappear method is called, I want to remove those UIImageViews with their UIViews alltogether, so that the memory gets freed up.
I call -release on the UIViews that contain the UIImageViews as subviews. Nothing else owns the UIImageViews. All I have is an instance variable to the UIView which groups the UIImageViews together.
So when I send -release to it, the retain count should become 0. But that's not a guarantee that I get more free memory, right? So, I also set myUIView = nil. Is that helpful / useful? How do you free up memory safely?

The best thing to do in -viewDidDisappear (not -viewWillDisappear; you're still onscreen at that point) for this case is to call self.view = nil. That will dump the entire view controller's view, which will be automatically reloaded for you next time it's needed.
If you have any IBOutlets on those views, you need to set them to nil, too or they won't release. Assuming you have a setup like this:
#interface MyViewController : UIViewController
{
UIImageView *_imageView;
}
#property (readwrite, retain) IBOutlet UIImageView *imageView;
#implementation MyViewController
#synthesize imageView = _imageView;
Then you need to call self.imageView = nil in your `-viewWillDisappear.
You generally should not call -release on your ivars except in their accessors and in -dealloc. The correct way to release them is to set them to nil using an accessor.
Caling -release when the retainCount is 1 will immediately call free(), which will recover memory. Remember, however, that other things may be retaining the object, including the autorelease pool, so you may not be certain what the retain count is at any given time.
I strongly advise people when they release a variable to immediately set it to nil. This doesn't impact the variable; it just protects you from chasing a pointer that you've released and so may now point to unallocated memory. So in -dealloc, I have lines that look like this:
[_stuff release]; _stuff = nil;
[_otherStuff release]; _otherStuff = nil;

Related

Correct way of releasing variables using Dealloc and ViewDidUnload

I've been trough some tutorials and some information, but I dont have a straight answer about the best way or the best place to release variables.
Lets see this situation, I have these 2 variables:
#property (nonatomic, strong) IBOutlet UIButton *myButton;
#property (nonatomic, strong) NSString *myString;
...
#synthesize myButton = _myButton, myString = _myString;
Is this the best way of releasing them?:
-(void)viewDidUnload {
self.myButton = nil;
self.myString = nil;
[super viewDidUnload];
}
-(void)dealloc{
[_myButton release];
[_myString release];
[super dealloc];
}
I understand more than enough when dealloc is called, and when viewDidUnload is called, I just want to know if that way is correct, and why it has to be done in that way.
Thanks guys
It is recommended to not use property accessor methods in init and dealloc, since they might expect some other information in the object to exist. If you know what you are doing, there is really no problem of using self.myButton = nil also in dealloc. However, there is really no use of setting them to nil since the object is being destroyed - unless some code is accidently run from dealloc (as the accessor methods I mentioned above).
In viewDidUnload, you want to set your members to nil instead of only releasing them, since your object will continue to exist and does not want to access dangling pointers.
So, your example should be the best performance and safest way of programming.
There are other ways, such as not declaring the IBOutlets as properties, or declaring them as properties without retaining. I find that in most cases I prefer to have them be retained properties, which I then have to explicitly release. An example of this is when you switch from one view controller to another. As one view controller is dismissed, its views are removed and they are released. Any IBOutlet UILabels on that view would get released too if I don't have them retained. That means that when I flip back to the old view, I have to go through and reset my labels and controls to their last values, when I could have easily kept them saved if I just retain the IBOutlet.
I have read the documentation about the use of the viewDidUnload method. I thought I did understand the meaning of this method
1) I use retain with #propery in the .h file and #syntesize in the .m-file. I assign object with a value using self.object = something. In this case I would set self.object = nil; in the viewDidUnload method.
2) I do not retain the object in the .h-file but I am allocing and init the object in the viewDidLoad method. In the dealloc method I have the [object release]; In the viewDidUnload method I also set [object release]; because the next time the view will appear, the object will be created in the viewDidLoad method
Hope, this will help you...

removeFromSuperview and release memory management

I have a MBProgressHUD that I allocate as follows:
self.progressHUD_ = [[[MBProgressHUD alloc] initWithView:self.view] autorelease];
if I call removeFromSuperview then would I have to call progressHUD release again? Also if I declare a property with something like this:
NSString * title_;
#property (nonatomic, retain) NSString * title_;
then it is guaranteed that in my dealloc I should have a release on title right?
If progressHUD_ is a retain property, then you will have to release it in dealloc. However, the nice thing about a retain property is that you only have to set it to nil to reclaim the memory; making sure to use "self." before.
e.g.
self.<property_name> = nil;
// or in your case
self.progressHUD_ = nil;
// the following will not release it because it's not accessing the property:
progressHUD_ = nil
I do not recommend using [progressHUD_ release] because it can cause problems. e.g. if elsewhere you had released progressHUD_ and not set it to nil, you may accidentally release a pointer which is no longer allocated (dangling pointer).
I also recommend calling self.progressHUD_ = nil; in viewDidUnload which is called during low memory conditions and the view is not showing. It doesn't kill your class instance, but just unloads the view. And of course this assumes that you call self.progressHUD_ = [[[MBProgressHUD alloc] initWithView:self.view] autorelease]; in viewDidLoad rather than in init...
No, you don't have to release it again. Views retain their subviews and release them again automatically when you call removeFromSuperview. As long as the view has been autoreleased when you attach it to the view, it will be released when it is removed from the view.
I didn't quite understand your second question, but yes, you have to release any properties of type "retain" or "copy" in your dealloc statement. You have to write those release statements manually, they aren't added automatically (unless you are using ARC of course, which I strongly recommend).
How is your progressHUD_ property defined? (btw, the ivar should have a trailing underscore, but not the property name).
In case it is defined as (retain, whatever), you will have to release it again:
When you create it, its retainCount is +1.
When you assign it to your property, its retainCount will be increased by one.
When you add it as a subview to the parent view, its retainCount will be increased by one.
At some point, autorelease will eventually decrease it by 1, but the view and the property still hold on to it.
So you'll have to either set your property to nil or call release on the ivar in your dealloc method.
Also, you probably want to use copy instead of retain when defining an NSString property. And yes: you'll have to release it either way.

iOS - What is best way to manage memory for IBOutlets?

I've been reviewing the Apple docs and sample code to try to determine the best way to manage memory for IBOutlets. I'm a little confused, to say the least.
The CurrentAddress sample code declares IBOutlets as properties:
#interface MapViewController : UIViewController <MKMapViewDelegate, MKReverseGeocoderDelegate>
{
MKMapView *mapView;
UIBarButtonItem *getAddressButton;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (nonatomic, retain) IBOutlet UIBarButtonItem *getAddressButton;
Great. And these are released in dealloc:
- (void)dealloc
{
[mapView release];
[getAddressButton release];
[super dealloc];
}
Now shouldn't these properties be set to assign? Because when set to retain, the IBOutlet's retain count will be increased twice: once when the nib is loaded and another time when the property is set? And wouldn't it be better to set these properties to nil instead of releasing in dealloc?
Apple docs says we should retain properties for iOS.
Retained outlets should be released and nil'ed in both dealloc and viewDidUnload.
On the Mac, every outlet which is not retained by a superview is automatically retained when loading the nib. That's not the case with iOS. That's why it's theoretically valid to only retain outlets other than views in the view hierarchy.
There's a very helpful post by Jeff LaMarche regarding this topic: Outlets, Cocoa vs. Cocoa Touch.
Once the nib loader finishes loading everything and connecting all the IBOutlets, it autoreleases all the objects it loaded. If your IBOutlet property was declared as assign, then the object it points to would be deleted next time the autorelease pool emptied.
You can set the properties to nil in dealloc instead of directly releasing them, the result is the same. The thing to watch for is, if you've provided your own implementation of the setter, you need to keep in mind that some of the other members of your object may already have been released.
This is different for MacOSX and iOS. In iOS the retain count will be two after the view is loaded and the nib connections are established.
Each of these elements will be retained once by the view and once by your controller. Additional elements in the view will be retained only by the view only.
When your controller releases the two elements, their retain count goes down to one. After that [super dealloc] is called. UIViewController has a [view release] in its dealloc, so the view is released (unless retained elsewhere, or previously released). When the view is deallocated, it releases its sub views, and the elements are finally completely freed.
The reason why [object release] is preferred in dealloc, is that key-value coding (or your own code) might cause additional code to be run when you write [self setObject:nil]. This can potentially cause other objects to interact with your controller when it is in the middle of deallocating itself. Setters should not be used in the init method for the same reason.
There is a second reason for just doing release. By leaving the value and not setting it to nil, we'll notice if code erroneously access that variable on our object later during dealloc. This can help catch bugs that might not be easy to track down otherwise.
I'm assuming you #synthesize these properties. If you didn't, you would need to release yourself manually. You are very correct in your assumption that if you continued to retain when a property is set, you would leak memory.
Let's think.... what did properties used to look like before we had the fancy #synthesize statement?
id _propertyName; // the ivar
- (id) propertyName {
return _propertyName;
}
- (void) setPropertyName:(id)v {
if (_propertyName) {
[_propertyName release]; // release the previously retained property
}
_propertyName = [v retain]; // retain this one so it doesn't fly away on us
}
Now, you don't need to type this stuff, because #synthesize is cool and generates that for you, it will also generate #synchronized blocks if you do not specify something as being nonatomic, which is also pretty rad.
If you specified assign instead of retain, you'd get something like this
id _propertyName; // the ivar
- (id) propertyName {
return _propertyName;
}
- (void) setPropertyName:(id)v {
_propertyName = v;
}
This is about the only thing you CAN do when things are not objects, because they are only values (also sometimes referred to as value types, objects are reference types). Since value types cannot be retained, the other type of block wouldn't make any sense. Go ahead and try to create a retain property with BOOL and watch what LLVM or GCC tell you to go do with what ;)
shouldn't these properties be set to
assign? Because when set to retain,
the IBOutlet's retain count will be
increased twice: once when the nib is
loaded and another time when the
property is set
well, the code you posted is right as it is.
when you use:
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
you are just telling xCode to create a setter method which will create your MKMapView object and retain it everytime you call
yourMapViewController.mapView = someMapView; // from out
// or
self.mapView = someMapView; // from in
after that mapView retain count increase +1
and your MapViewController code need that 'couse now you can point to mapView and manage it...
don't worry for the IB nib file...
when you load a UIViewController with a nib, in your case the class
MapViewController : UIViewController, the IB nib objects will release when you release your MapViewController...
just care of the objectS you retain...

Where I should call [object release]?

I've subclassed some UITextField and added some custom properties.
In a UITableViewController, in the ViewDiDLoad I init them, and in the cellForRowAtIndexPath I add them to the cell with [cell.contentView addSubview:customTextField];
Each cell has a different customTextField as all of them are very different.
Where I should call the [customTextField release] ?
After I add them to the cell view ?
If for example I call [self.tableView reloadData] my customTextField are going to be added again to the cell, so maybe I should change my approach in doing this ?
thanks for the orientation ...
regards,
r.
You release an object when you no longer have any interest in it. This happens for many reasons; it might be because you've finished with the object, or have passed the control over the object lifetime to another object. It might be because you're about to replace the object with a fresh instance, it might be because you (the owner object) are about to die.
The last one seems to be relevant in your case. You create these object in viewDidLoad and repeatedly need them (i.e. to add them to cells) until your object is no longer functioning. In this case, just as you create them in viewDidLoad, you can release them in viewDidUnload.
Edit: I should really mention autorelease, but this isn't relevant in this instance. Memory management is best handled with a notion of 'owner' - the person who creates something (or retains it) should be responsible for deleting it (or releaseing in ObjC parlance). autorelease handle some cases where you need to give an object to an alternate owner, having previously owned it yourself (typically via a method return). If you are the creator, you can't just release it before returning it to the new owner, as it will be deleted before the new owner has a chance to stake an interest in it. However, you can't just not release it; it will leak. As such, the system provides a big list of objects that it will release on your behalf at some point in the future. You pass your release responsibility to this list, then return the object to the new owner. This list (the autorelease pool) ensures your release will occur at some point, but gives the new owner a chance to claim the object as theirs before it's released.
In your case, you have a clear interest in owning the objects for the lifetime of your view controller - you need to, at any time, be able to add them to view cells in response to a table data reload. You're only done with them when your view controller dies, so the viewDidUnload (or possibly dealloc) is the only sensible place to release them.
I always release my controls directly after I added them to a view using addSubView. When I work with tables, I also initialize them in the cellForRowAtIndexPath method.
Therefor the object stays alive the shortest time.
Adam Wright explains the theory of this very well, but let me give you some practice. You're thinking about this problem far too hard, and that almost always leads to bugs. There is a simple solution that solves this problem almost every time: Retain all ivars using accessors; don't retain non-ivars.
.h
#interface ... {
UITextField *_customTextField;
}
.m
#property (nonatomic, readwrite, retain) UITextField *customTextField;
...
#synthesize customTextField=_customTextField;
-(void)viewDiDLoad {
self.customTextField = [[[UITextField alloc] init....] autorelease];
}
...
- (void)dealloc {
// I do not recommend accessors in dealloc; but everywhere else I do
[_customTextField release]; _customTextField = nil;
}
Never access your ivars directly, except in dealloc (even that is controversial and some people recommend self.customTextField = nil; in dealloc; there are arguments either way). But never assign your ivars directly. If you will follow this rule, you will find that most of your memory problems go away.
The safest way to handle object ownership is to autorelease the view directly after initialization:
FooTextField* textField = [[[FooTextField alloc] init] autorelease];
[myCell.contentView addSubview:textField];
Adding the text field to a superview (the UITableViewCell's contentView) retains it. This way you don't have to care about releasing the view afterwards.
There seems to be a resentment against autorelease in the iPhone developer community. In my opinion, this resentment is unfounded. Autoreleasing an object adds very little overhead to the program if the objects lives longer than the current pass through the run loop.
Every object in Obj-C has a reference counter (retainCount), and when this counter goes to 0 the object is deallocated. When you allocate and initialize an object, the reference count is set to 1 - but you can retain it as many times you want to.
UITextField *textField = [[UITextField alloc] init]; // Reference counter = 1
[textField retain]; // Reference counter = 2
[textField retain]; // Reference counter = 3
The opposite of retain is release, which subtracts from the reference counter;
...
[textField release]; // Reference counter = 2
[textField release]; // Reference counter = 1
You can always get the reference counter of your objects;
printf("Retain count: %i", [textField retainCount]);
The method addSubview of UIView does retain your passed in sub view - and when it's done with it it releases it. If you need your UITextField later, in another scope (when the UIView is done with it and has released it) - you should not release it after you've added it to the super view. Most of the time you actually don't need to hold on to a reference, so you should release it after you've added it to the super view. If you dont - you can release it in the dealloc method of your scope.
Take a look at UITableView -dequeueReusableCellWithIdentifier: and -initWithStyle:reuseIdentifier:.
In -tableView:cellForRowAtIndexPath:, use -dequeueReusableCellWithIdentifier: and check if the result is nil. If it is, instantiate a new cell with -initWithStyle:reuseIdentifier:.
Send -autorelease to your customTextField upon creation and adding to the respective cell.
You should not add subview in cellForRowAtIndexPath! This will slow down the view as you add a subview each time the cell is displayed. Try using custom UITableViewCell class for that purpose.
Here is a perfect solution of UITableView customization
http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html
works jut perfectly

Objective C iPhone when to set object references to nil

I have been developing with objective C and the Cocoa framework for quite some time now. However it is still not absolutely clear to me, when am I supposed to set object references to nil. I know it is recommended to do so right before releasing an object that has a delegate and you should also do so in the viewDidUnload method for retained subviews. But exactly when should this be done and why?. What does it accomplish exactly?. Thank you in advance.
-Oscar
Say you have a pointer myView defined in your class' interface:
#interface MyClass {
UIView *myView;
}
#end
Then in your code, at some point, you may release that variable:
[myView release];
After you do that, myView, the pointer, won't be pointing to nil, but will be pointing to a memory address of an object that may not exist anymore (since you just released it). So, if you happen to do something after this, like:
[myView addSubview:otherView];
you'll get an error.
If, on the other hand, you do this:
[myView release];
myView = nil;
...
[myView addSubview:otherView];
the call to addSubview will not have any negative impact, since messages to nil are ignored.
As a corollary, you may see suggestions of using retain properties, such as:
#property(retain) UIView *myView;
and then in the code, just do:
self.myView = nil;
By doing that, the synthesized accessor will release the old object and set the reference to nil in one line of code. This may prove useful if you want to make sure all your properties are both released and set to nil.
One thing that you must never forget, is that memory management is done by means of retain release calls, and not by means of assigning nil. If you have an object with a retain count of 1, and assign nil to it's sole variable, you'll be leaking memory:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0,10,10)];
view = nil;
// You just leaked a UIView instance!!!