iPhone Method Questions (dealloc an viewDidUnload) - iphone

I have been working on an app, and the book I read said to put these statements into the viewDidUnload and dealloc methods. What other information should go here? I have buttons and labels in my program. Do I need to do anything for them?
I want an efficiently running application.
Here's my code:
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.doublePicker = nil;
self.color = nil;
self.choice = nil;
[super viewDidUnload];
}
- (void)dealloc {
[doublePicker release];
[color release];
[choice release];
[super dealloc];
}

You should only release your IBOutlets and other UI elements in viewDidUnload. All the other data that you allocated in your view controller (as well as the IBOutlets) should be released in the dealloc method. That's because the view can be loaded and unloaded multiple times during the lifetime of a view controller. For example, a view can be unloaded if it is not visible, but the data behind it (in the view controller) still needs to be kept in memory. When both the view and its controller are no longer needed, the dealloc method is called.

The code you posted is correct, but you should also create properties for your outlets, like so:
in your .h file:
#property (nonatomic, retain) UIPickerView *doublePicker;
#property (nonatomic, retain) UIPickerView *color;
// ...etc
in your .m file:
#synthesize doublePicker;
#synthesize color;
// ...etc
There is some debate about this technique (explicitly retaining your outlets and releasing them like this), but it is the technique that Apple recommends:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmNibObjects.html#//apple_ref/doc/uid/TP40004998-SW2

The general rule is that you want to call release on anything that you alloc or init. Components that you create in xib's do not need to be released.

Related

How to Release golable instance variables in ARC mode

i have created multiple insances in my h file
IBOutlet UIImageView *imageView;
IBOutlet UIImageView *subImageView;
IBOutlet UIImageView *arrowRight;
IBOutlet UIImageView *arrowLeft;
IBOutlet UIImageView *arrowDown;
My project is in the ARC mode
do i have to set them to nil in dealloc () method inorder to release them??
Thanks
If you don't need the global instances after one of your objects is deallocated, the best way would be to set the global pointers to nil in dealloc.
- (void)dealloc {
gYourGlobalPointer = nil;
}
Note that in ARC you can't call [super dealloc], dealloc will be sent to your superclass automatically.
you can make them nil in viewDidUnload as following:
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
self.myOutlet = nil;
}
in ARC you don't have to worry about releasing instance veritable of a property at all. Compiler will take care of them for you.
If you want to release manually you have to assign nil to all strong variables pointing to particular instance.

IBOutlet UITextView is nil after calling another class initWithNibName and back to the class using method

My problem is that in ProductNote class UIButton Action I did initWithNibName Notes Class to show the popOver with a UITableView in Notes Class. I am fetching data from sqlite and then load it to UITableView in tableViewDidSelectRowAtindexPath:. I got the selectedNote and creates object of ProductNote Class to call selectedNote instance method that only set IBOutlet's textview.text but its nil. Thats my problem, Below is the code please help me to knowing why i face this type of issue. I am using Xcode 4.3.3 and not using ARC. Manually I defined dealloc method on every ViewController
//**ProductNote.h Class****************************
#import <UIKit/UIKit.h>
#class Notes;
#interface ProductNote : UIViewController<UIPopoverControllerDelegate>
{
UIPopoverController *popOverController;
UITextView *txtmesssagenotes;
Notes *objNotes;
}
#property (retain, nonatomic) IBOutlet UITextView *txtmesssagenotes; //It is Connected to ProductNote.xib
#property (retain,nonatomic) UIPopoverController *popOverController;
#property (retain,nonatomic) Notes *objNotes;
-(IBAction)presentPopOver:(UIButton*)sender;
-(void)selectedNote:(NSString*)note;
#end
//ProductNote.m Class
#implementation ProductNote
#synthesize txtmesssagenotes,popOverController,objNotes;
-(IBAction)presentPopOver:(UIButton*)sender
{
self.objNotes=[[Notes alloc]initWithNibName:#"Notes"bundle:nil];
UIPopoverController *popOver=[[[UIPopoverController alloc]initWithContentViewController:objNotes]autorelease];
self.popOverController=popOver;
self.popOverController.delegate=self;
self.popOverController.popoverContentSize=objNotes.view.frame.size;
CGRect rect=[self.view convertRect:objNotes.view.frame fromView:self.view];
rect.origin.y+=110;
rect.origin.x+=23;
[self.popOverController presentPopoverFromRect:rect inView:self.view permittedArrowDirections:0 animated:YES];
//Then I get popOver with tableview
}
-(void)selectedNote:(NSString*)note
{
self.txtmesssagenotes.text=note;
//Here I am getting txtmesssagenotes=0X0 or nil. Using self or without self Please tell me the reason.
}
- (void)dealloc {
[txtmesssagenotes release];
[popOverController release];
[objNotes release];
[super dealloc];
}
#end
#interface Notes : UITableViewController
{
NSMutableArray *arrNotes;
NSString *selectedNote;
UITableView *tblNotes;
}
#property(nonatomic,retain)NSMutableArray *arrNotes;
#property(nonatomic,retain)NSString *selectedNote;
#property(nonatomic,retain)IBOutlet UITableView *tblNotes;
#end
//Actually I skip the other methods that makes larger program to read . other methods only used to fetch data from sqlite and fill up the arrNotes that is used to fill all rows in the tableview.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedNote=[self.arrNotes objectAtIndex:indexPath.row];
//Here self.arrNotes valid object and contains the data, and assigns NSString object to self.selectedNote
ProductNote *productNote=[[ProductNote alloc]init];
[productNote selectedNote:self.selectedNote]; //after calling selectedNote i goto to selectedNote implementation or definition above.
[productNote release];
}
-(void)dealloc
{
[arrNotes release];
[selectedNote release];
[tblNotes release];
[super dealloc];
}
It is because just as you stated that txtmesssagenotes was created using IB. And you never presented your ProductNote UIViewController instant productNote. So the txtmesssagenotes was never allocated and initialized properly.
Are you calling selectedNote: before your view has loaded?
Just because you created a view controller with a xib doesn't mean that it loads all your subviews immediately.
The xib is parsed and all your views are created the first time that the view controller's view property is asked for - this is usually just before it appears for the first time.
Until then, all the IBOutlet connections will be nil.
You need to store the text for your note as an NSString property of you view controller. Then, inside either viewDidLoad you need to call self.txtmesssagenotes.text=self.note; - viewDidLoad is automatically called just after your view is loaded so you are guaranteed to have all your IBOutlets set by then.
You shouldn't rely on your view objects to store the state of your app (in this case, the text of the note). If a low memory warning is received while your view controller isn't visible then all your view objects will be deleted - they will only be recreated when your view controller becomes visible again - if you are storing your note string inside a UITextView then it might no be there the next time you ask for it :) You should always store data in a property of your view controller (or somewhere else you control) and create your views using it.

Releasing Outlets in a NavigationController

I have literally 24 IBOutlets in one view of a NavigationController (none are retained as properties). Is there a good way to release these? I have a feeling they are causing memory issues in slower 3G and 3GS devices.
No ARC
Any thoughts?
As you push UIViewControllers on to a UINavigationController, the view of the UIViewControllers which have been "pushed onto" may be unloaded to save memory (as they are invisible). The views are then reloaded when necessary (and you get the viewDidLoad callback). You should have IBOutlets to UIViewControllers not UINavigationController so that they can be released on viewDidUnload. The usual way to release them is to declare them as retained properties and set them to nil (with the self.outlet accessor) in viewDidUnload and dealloc. Or just use ARC.
ViewController.h
#interface ViewController : UIViewController
{
}
#property (retain, nonatomic) IBOutlet UILabel *myLabel;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize myLabel;
#pragma mark - View lifecycle
- (void)viewDidUnload
{
[self setMyLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[myLabel release];
[super dealloc];
}
#end

Objects in nib file not associating with IBOutlet objects in code

OK I'm pulling my hair on on this, it makes no sense so it must either be a bug, or some extremely stupid mistake I'm making.
Here's the situation: I have a UIViewController with a xib file. It has a UIView hooked up to the view property, a UIImageView hooked up to a property called imageView, and a UISegmentedControl hooked up to segmentControl.
Yet in my code, I'm unable to assign an image to the image view. When I NSLog the object, I'm getting the address of 0x0, so it's not associating at all. I have the bindings set up in Interface builder, I've restarted XCode and clean and built the project. Nothing is working and I've wasted a stupid amount of time trying to figure this out at this point. I've also NSLoged the segmentControl object and am getting 0x0 as well. So nothing from the XIB is hooking up with the code, but the XIB itself is loading because the objects are displayed on the screen.
Does anyone have any ideas offhand of what I could be missing? This is such a simple thing, it's incredibly frustrating that it's refusing to work all of a sudden.
Here's the code below, in this case I'm accessing the objects in the setter for projectId, but I also tried accessing the imageView from another class and it didn't work either (and yes I had a #property declaration and synthesize for imageView when I tried).
DiagramViewController.h:
#import <UIKit/UIKit.h>
#interface DiagramViewController : UIViewController
{
NSUInteger projectId;
IBOutlet UIImageView *imageView;
IBOutlet UISegmentedControl *segmentControl;
}
#property NSUInteger projectId;
#end
DiagramViewController.m:
#import "DiagramViewController.h"
#implementation DiagramViewController
#synthesize projectId;
-(void)setProjectId:(NSUInteger)projId
{
NSLog(#"imageView: %#", imageView);
NSLog(#"segmentControl: %#", segmentControl);
projectId = projId;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%i_schem", projectId] ofType:#"png" inDirectory:#"project-details/images/diagrams"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
imageView.image = [UIImage imageWithData:imageData];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
And here's an image of the Interface Builder hookups:
You need to make sure you're doing this in the -viewDidLoad method, otherwise the nib file hasn't actually unarchived the objects and thus they will be set to nil. In particular, you can't access items from the nib within an -init method.
Without seeing your code however, it's hard to say if this is the case for you.
EDIT: Ok, thanks for posting code. When does -setProjectId: get invoked? Are you sure the nib has finished loading at this point? You have no viewDidLoad method in your view controller so it appears you never check for this at any time.
See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
viewDidLoad
Called after the controller’s view is loaded into memory.
(void)viewDidLoad
Discussion
This method is called after the view controller has loaded its associated views into memory. This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method. This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
Sounds like something went wrong when you wired up the IBOutlets.
In IB right click on the UISegmentedControl and post a screenshot so that we can see what you have there. If you see anything 'yellow' then you may have found your problem.

when/where should properties be released once the objects is pushed for display?

I've defined a view controller with an array as one of its properties, and set the array with an allocated and autoreleased array.
After I push the view for display I release it.
By watching the leaks tool I see that every time that I pop the view I suffer from leakage.
I tried to release the properties explicitly, immediately after the push but the app crashes.
looking forward for your suggestions.
The leak is probably because of the array property is set to retain, like so:
#property (nonatomic, retain) NSArray *yourArray;
Your autorelease object is retained on assignment to the yourArray property. Since it is retained, you have to release it in the controller's dealloc method:
- (void) dealloc {
[yourArray release], yourArray = nil;
[super dealloc];
}
HTH.