I have two classes:
RootViewController.h
RootViewController.m
In my RootViewController.h
// in .h file
UITextField* myTextField_;
#property (nonatomic, retain) UITextField* myTextField.
In my RootViewController.m
// in .m file
#synthesize myTextField = myTextField_
// in dealloc
[myTextField_ release]
// in viewDidLoad
UITextField* tf = [[UITextField alloc] init] initWithFrame:CGRectMake(200,6,100,30)];
[nameTextField_ = tf];
[tf release]
My question is,
Does that create any memory leaks? Or will that crash? Are there better ways to create an instance of UITextField so I keep a reference to it? Perhaps
myTextField_ = [[UITextField alloc] init] initWithFrame:CGRectMake(200,6,100,30)];
would that be sufficient?
The simpliest way is to do this like this:
.h:
UITextField *myTextField;
#property (nonatomic, retain) UITextField *myTextField;
.m
#synthesize myTextField;
- (void)viewDidLoad {
myTextField = [[UITextField alloc] initWithFrame:CGRectMake(200,6,100,30)];
}
- (void)dealloc {
[myTextField release];
}
You will have one instance which is allocated and released in most clean way and you will have reference to this textfield all the time.
You should not do [tf release] as you are accessing your variable directly.
If you access it via self. notation that it will be called [tf retain] and then you should release tf. So in your current version all is ok besides line where you are releasing.
[nameTextField_ = tf];
change:
[self setMyTextField:tf]
Yes, this will do:
myTextField_ = [[UITextField alloc] initWithFrame:CGRectMake(200,6,100,30)];
You can also use this:
self.myTextField = [[UITextField alloc] initWithFrame:CGRectMake(200,6,100,30)] autorelease];
(when using the property it will retain, when using directly the member myTextField_ it won't (automatically) retain). Also alloc will set retainCount to 1 so it will eventually need to be released (in your case in dealloc method you can use either [myTextField_ release]; or self.myTextField=nil;);
Not sure what this is (I believe it will show up some compile errors):
[nameTextField_ = tf];
Related
I am having a Navigation based app with a few buttons on the first View (not using ARC). By touching one button optionPressed gets triggered to push to another View.
When I analyse the code for leaks. I get the following warning. "Potential leak of an object" [self.displayViewController setCurrentPhoto:sender.currentTitle];
How should I release the self.displayViewController and where if that's the cause.
.h
#import <UIKit/UIKit.h>
#import "DisplayViewController.h"
#class DisplayViewController;
#interface Pocket_DjangoViewController : UIViewController
- (IBAction)optionPressed:(UIButton *)sender;
#property (retain, nonatomic) DisplayViewController *displayViewController;
#end
.m
- (IBAction)optionPressed:(UIButton *)sender
{
if (!self.displayViewController) {
self.displayViewController = [[DisplayViewController alloc] initWithNibName:#"DisplayViewController" bundle:nil];
}
[self.displayViewController setCurrentPhoto:sender.currentTitle];
[self.navigationController pushViewController:self.displayViewController animated:YES];
//[self.displayViewController release];
//self.displayViewController = nil;
}
The leak stems for this line:
self.displayViewController = [[DisplayViewController alloc] initWithNibName:#"DisplayViewController" bundle:nil];
you should have:
self.displayViewController = [[[DisplayViewController alloc] initWithNibName:#"DisplayViewController" bundle:nil] autorelease];
In your actual code, you are creating an object:
[[DisplayViewController alloc] initWithNibName:#"DisplayViewController" bundle:nil];
which is already retained; then you assign it to a retain property:
#property (retain, nonatomic) DisplayViewController *displayViewController;
and this will create a retain unbalance, as the original alloc is never released and only the retain called by the property is eventually released.
Suppose I have two classes. In the first one I declare this in Class1.h
#interface Class1 : UIViewController {
NSString *myString;
id myObject;
}
On the second class I go beyond that I declare it like
#interface Class2 : UIViewController {
NSString *myString;
id myObject;
}
#property (nonatomic, retain) NSString *myString;
#property (nonatomic, retain) id myObject;
and then I #synthesize myString, myObject on Class2.m
Then, on my main program, I create two objects: one based on Class1 and another one based on Class2.
What effect the #property of class2 will have? Will every value assigned to both values on Class2 be always retained? If so, do I need to "release" them? How?
Thanks.
Please read Declared Properties section of The Objective-C programming language
for a full explanation on properties ;)
In Class2:
In this case you set retain attribute to your property it is supposed to be retained in the implementation. This is done automatically when you synthesize a property.
This means that you should have
- (void) dealloc{
[myString release];
[myObject release];
[super dealloc];
}
and everything should be fine
In Class1, you don't have properties so myString and myObject is not visible from outside. But this does not mean that you shouldn't release them. It depends on the way you initialize them and/or if you send retain messages to them.
BTW, if you set assign a property you don't release it, just set it to nil in the dealloc method. If you set copy to it then you must release it.
EDIT
You said: *But suppose I have this *
#property (nonatomic, retain) UIView *myView;
and
myView = [[UIView alloc] initWithFrame:myFrame];
[self.view addSubview:myView];
[myView release];
? I am already releasing myView... do I have to release it again???
First, since you have your property defined that way, you should have dealloc method as:
- (void) dealloc{
[myView release];
[super dealloc];
}
So, the answer is NO you should not release it but actually is not correct.
Please take a look:
myView = [[UIView alloc] initWithFrame:myFrame]; //myView retainCount is 1
[self.view addSubview:myView]; //retainCount is 2
[myView release]; //retainCount is 1 again
later in dealloc method
- (void) dealloc{
[myView release]; // retainCount becomes 0, is deallocated
[super dealloc]; // subviews of self.view are released but myView was already deallocated!, so you have over released myView once ;(
}
This is the correct way: (Use your properties ;) )
UIView *aView = [[UIView alloc] initWithFrame:myFrame]; // init, retainCount is 1
self.myView = aView; // retainCount becomes 2
[aView release]; // retainCount becomes 1 again and we are fine.
[self.view addSubview:self.myView]; //retainCounts becomes 2 again.
even if it is 2 there is no problem because when self.view is deallocated its subviews also will be released. Hence self.myView retainCount will become 1 again later when self is deallocated.
- (void) dealloc{
[myView release]; //retainCounts becomes 1
[super dealloc]; // all its subviews of self.view are released hence myView retaincount becomes 1 and is released corretly
}
What is the difference?
Suppose self.myView is also retained by other object X and with the former approach, X's view will be pointing to an invalid object, because it was already released.
Hope it helps
EDIT2
As bbum's indication, this is a mini-mini-short tutorial on properties:
when you have
#property (... retain) NSObject *retainVar;
#property (... assign) NSObject *assignVar;
#property (... copy) NSObject *copyVar;
and you #synthesize them
is like having the following setters:
// retain
-(void)setRetainVar:(NSObject *)var {
if (retainVar != var) {
[retainVar release];
retainVar = [var retain];
}
}
//assign
-(void)setAssignVar:(NSObject *)var {
assignVar = var;
}
//copy
-(void)setCopyVar:(NSObject *)var {
if (copyVar != var) {
[copyVar release];
copyVar = [var copy];
}
}
(this means that if you assign directly an object you have to make sure is something equivalent to above setters, from the memory management point of view)
and your dealloc method should be something like:
- (void) dealloc{
[retainVar release];
assignVar = nil;
[copyVar release];
[super dealloc];
}
When setting your ivars
for example, inside of init:
- (id) init{
if ((self = [super init])){
//this is ok
retainVar = [[NSObject alloc] init];//but is retainVar was not nil we will have a leak ;(
//This is better
NSObject *obj = [NSObject alloc] init];
self.retainVar = obj;
[obj release];
//this is BAD
assignVar = [[NSObject alloc] init];//because this is like retaining it, later it will leak
//below is correct
NSObject *obj = [[[NSObject alloc] init] autorelease];
assignVar = obj;
//copy is pretty much like retain,
//this is ok
copyVar = [[NSObject alloc] init]; //but, if copyVar was not nil is a leak!
//below is better
NSObject *obj = [NSObject alloc] init]:
self.retainVar = obj;
[obj release];
}
return self;
}
Apple's "Learning Objective C - A Primer" tells you about that and more:
http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/
I'm my class i've added a an instance of my view controller, created a property and then synthesized it in my implementation file. I am trying to update the UIlabel in the view controller like this,
NSString *currentChar = [[NSString alloc] initWithFormat:#"%c", ch];
viewController.outputLabel.text = currentChar;
[currentChar release];
My problem is that everything builds without any errors or warnings but the label just doesn't get updated, what am I doing wrong. I'd really appreciate some help on this one.
Are you sure you're referencing the existing viewController and you didn't instantiate a new one? Your property is not declared as copy, correct?
textProcessor.h / .m
#interface textProcessor : NSObject {
MainViewController *mainView;
}
#property (retain) MainViewController *mainView;
#end
#implementation textProcessor;
#synthesize mainView;
MainViewController.h / .m
#interface MainViewController : UIViewController {
UILabel *myLabel;
}
#property (retain) UILabel myLabel;
#end
#implementation MainViewController
#synthesize myLabel;
When you are initializing your textProcessor class, and you set the value for "mainView" like
-(void)viewDidLoad {
[super viewDidLoad];
textProcessor *proc = [[textProcessor alloc] init];
proc.mainView = self;
//note that you are not doing this:
//MainViewController *mainView = [[MainViewController alloc] init];
//proc.mainView = mainView;
//that was creating a new instance variable instead of using self, the existing one
[textProcessor release];
}
Have you created your label in IB? If you are using IB you have to create an IBOutlet for your UILabel. You then make a connection between the UILabel in IB to your IBOutlet in your class.
Have you tried calling the setNeedsDisplay method on the view? Also you may want to try using the setText method instead of assigning directly to the property.
So, I'm loading by XIB file and it contains a set of UIBarButtonItems. Some of the items are used when the viewDidLoad: is called.
#interface MyViewController : UIViewController {
IBOutlet UIBarButtonItem *addButton;
IBOutlet UIBarButtonItem *editButton;
IBOutlet UIBarButtonItem *doneButton;
}
// NB: There are no properties retaining anything.
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *initialToolbarItems =
[[NSArray alloc] initWithObjects: addButton, editButton, nil];
self.toolbarItems = initialToolbarItems;
[initialToolbarItems release];
}
- (void)dealloc {
[super dealloc];
// Nothing else to do here since we are not retaining anything.
// … or are we? <insert dramatic music here>
}
#end
If I push the above the above ViewController onto a UINavigationController everything seems fine, all the IBOutlets are assigned and behave like expected.
The instant i pop the ViewController from the navigation stack Instruments' Leaks tells me that I am leaking a UIBarButtonItem. Woe is me!
If I change dealloc: to
- (void)dealloc {
[doneButton release];
[super dealloc];
}
no leaks occur. The same goes if I use doneButton in viewDidLoad:
NSArray *initialToolbarItems =
[[NSArray alloc] initWithObjects: addButton, editButton, doneButton, nil];
My question: Why is my IBOutlet leaking when I don't use it. I don't retain it at any point. The the NIB loader should own the object, right?
Only thing I can think of:
The nib loader treats IBOutlets as strong references. All outlets are retained by default unless you specifically indicate assign. So you still need to release them in dealloc and viewDidUnload.
You can also use a assigned property to make it a weak reference:
#property (nonatomic, assign) IBOutlet UIBarButtonItem *doneButton;
Some reading: http://weblog.bignerdranch.com/?p=95
If you have #property with (retain) declared for the your IBOOutlets they will be retained and must be released
The array retains them
I'm writing an iPhone app. I have a header file that looks like this:
#interface EditTagsViewController : UITableViewController {
NSMutableArray *allTags;
NSMutableArray *selectedTags;
NSInteger currentFavorite;
}
#property (nonatomic, retain) NSMutableArray *allTags;
#property (nonatomic, retain) NSMutableArray *selectedTags;
#property (nonatomic) NSInteger currentFavorite;
#end
In the implementation file, my viewDidLoad method looks like this:
- (void)viewDidLoad {
NSMutableArray *aTags = [[NSMutableArray alloc] initWithArray:[Tag findAllTags]];
self.allTags = aTags;
[aTags release];
NSMutableArray *sTags = [[NSMutableArray alloc] initWithArray:[Tag findByFavoriteId:currentFavorite]];
self.selectedTags = sTags;
[sTags release];
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNewTag:)];
self.navigationItem.rightBarButtonItem = add;
[add release];
[super viewDidLoad];
}
Here is my dealloc method:
- (void)dealloc {
[allTags release];
[selectedTags release];
[super dealloc];
}
What's confusing to me is that when I run the app both in the simulator and on the device itself, using Instruments (memory leaks), it tells me that this line in my viewDidLoad method is leaking an array:
self.selectedTags = sTags;
It's confusing because I'm using the exact same technique with 2 different variables, and yet no leak is reported with the first one.
I feel like I'm missing something obvious here. Any ideas?
Your code looks correct to me. Is it possible that one of [Tag findAllTags] or [Tag findByFavoriteId:] is leaking? Are you making sure to set self.allTags and self.selectedTags to nil in dealloc?
Be mindful of the difference between saying self.allTags = ... and allTags = .... Because allTags is a property and has the retain attribute, whenever you assign via self.allTags = ..., it implicitly calls the setter method [self setAllTags:...], which invokes retain on the new value and release on the old value (if any). You're doing it correctly in this code sample, but if elsewhere you're assigning straight to allTags (without the self.), you're not releaseing the old value, which may be the source of the leak. Likewise for selectedTags.
Have a look at findByFavoriteId is there a retain there? That is the only difference I can see between the aTags and sTags are used in your example