In dealloc method set any delegate to nil is needed or not needed - iphone

I have created tableview in my view by programmatic like below
table = [[UITableView alloc] initWithFrame:CGRectMake(0, 44, 320, 370) style:UITableViewCellStyleDefault];
table.delegate = self;
table.dataSource = self;
table.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:table];
in dealloc method i write like below
table.delegate = nil;
table.dataSource = nil;
[table release];
table=nil;
this the better way or below one is better
[table release];
table=nil;
I want to know if i dont reset delegate and dataSource what will happen
Thanq

If you are deallocating an object that acts as the delegate to other objects, you need to make sure that you have set their delegates to nil, before you call [super dealloc] (assuming the normal pattern that objects do not retain their delegates). This is because when [super dealloc] has returned, this object is no longer a valid object and the objects it is a delegate to effectively have dangling references, if they have not been set to nil.
In this particular case, you would probably get away without doing it because your object's dealloc probably won't get called except when the UI is being dismantled and the table view no longer needs to use its delegate or data source, but don't bet on it.

From Setting delegate to nil in dealloc:
It's a defensive programming move. It's clearing out the reference to the delegate object incase something else in your object tries to access the delegate after you've told it that you're done with it. As part of your dealloc you might have a method or do something that triggers a KVO notification that makes a call to the delegate. So setting the delegate's reference to nil prevents that from happening. If it did happen you could end up with some oddball crashes that are fun to reproduce and fix.

To add to the answers above, you do not need
table = nil;
in your dealloc. It won't hurt, but it is not necessary to nil out your ivars. Your view is being dealloc'ed and therefore your ivars will no longer be accessible. You are probably confusing that with:
self.table = nil;
which can function as an alternative way to release if you are accessing the ivar via a property.
Of course if you have ARC turned on, then you don't need the release at all.
And to answer your actual question, if you don't nil out the table's delegate and datasource on the dealloc of the view....nothing will happen. They are set to the view, which is in the process of being released. In this case, you will have no issues not doing it. In theory it's good form.

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...

Inserting subView - iPhone

- (void)viewDidLoad {
BlueViewController *blueController = [[BlueViewController alloc] initWithNibName#"BlueView" bundle:nil];
self.blueViewController = blueController; //blueViewController set to var above
[self.view insertSubview:blueController.view atIndex:0];
[blueController release];
[super viewDidLoad];
}
not understanding this code very well. How come i am inserting the subview blueController and not self.blueViewController
also what difference does it make if I don't use self. Not even sure why self is used. I interpret it as I am setting the blueViewController property of the current View Controller to the blueController instance but why would I do that. The book I am reading from does not explain such things in detail. It is pretty much monkey do this.
not understanding this code very well. How come i am inserting the subview blueController and not self.blueViewController
since you have executed the assignment:
self.blueViewController = blueController;
those two variables are the same, so
[self.view insertSubview:self.blueController.view atIndex:0];
would be just the same as the code you posted.
also what difference does it make if I don't use self. Not even sure why self is used. I interpret it as I am setting the blueViewController property of the current View Controller to the blueController instance but why would I do that. The book I am reading from does not explain such things in detail. It is pretty much monkey do this.
if you don't assign to self.blueController, then your variable is just a simple variable local to that function. By having a property self.blueController and storing there a value, you can use that value in all of the selectors (functions) of your class.
check the code and you will see that self.blueController is used also in other functions. e.g., at some point you might decide you like making that subview hidden, or you want to remove it, etc. All of this you can do only if you have a pointer to the controller accessible to your class functions.
self is used if you are referring to an object of the class.
While initializing a variable we must use self. This will increment blueViewController retainCount to 1.
self.blueViewController = blueController;
While inserting also you can use both. Results will be same.
[self.view insertSubview:blueController.view atIndex:0];
[self.view insertSubview:self.blueController.view atIndex:0];
blueController is an alloced and initialized object while blueViewController is just a pointer to the BlueViewController class.By writing
self.blueViewController = blueController
you retain the blueController object.If you do not use self you won't be ratining the object and after you release it at line
[blueController release];
your program will crash as soon as you refer to it again.

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

Is it better to autorelease or release right after?

There are a lot of cases in which one would alloc an instance, and release it right after it's being assigned to something else, which retains it internally.
For example,
UIView *view = [[UIView alloc] initWithFrame...];
[self addSubView:view];
[view release];
I have heard people suggesting that we go with autorelease rather than release right after.
So the above becomes:
UIView *view = [[[UIView alloc] initWithFrame...] autorelease];
[self addSubView:view];
What's the best practice here? Pros and cons?
In most cases, it wont really matter either way. Since -autorelease simply means that the object will be released at the end of the current iteration of the run loop, the object will get released either way.
The biggest benefit of using -autorelease is that you don't have to worry about the lifetime of the object in the context of your method. So, if you decide later that you want to do something with an object several lines after it was last used, you don't need to worry about moving your call to -release.
The main instance when using -release will make a noticeable difference vs. using -autorelease is if you're creating a lot of temporary objects in your method. For example, consider the following method:
- (void)someMethod {
NSUInteger i = 0;
while (i < 100000) {
id tempObject = [[[SomeClass alloc] init] autorelease];
// Do something with tempObject
i++;
}
}
By the time this method ends, you've got 100,000 objects sitting in the autorelease pool waiting to be released. Depending on the class of tempObject, this may or may not be a major problem on the desktop, but it most certainly would be on the memory-constrained iPhone. Thus, you should really use -release over -autorelease if you're allocating many temporary objects. But, for many/most uses, you wont see any major differences between the two.
I agree with Matt Ball. Let me just add that, if you find yourself using this pattern frequently, it can be handy to write a quick category:
#interface UIView (MyCategories)
- (UIView *)addNewSubviewOfType:(Class)viewType inFrame:(NSRect)frame;
#end
#implementation UIView (MyCategories)
- (UIView *)addNewSubviewOfType:(Class)viewType inFrame:(NSRect)frame
{
UIView * newView = [[viewType alloc] initWithFrame:frame];
[self addSubView:newView];
return [newView autorelease];
}
#end
Which can be used as follows:
UIView * view = [someView addNewSubviewOfType:[UIView class]
inFrame:someFrame];
And it even works with other types, as long as they are derived from UIView:
UIButton * button = [mainView addNewSubviewOfType:[UIButton class]
inFrame:buttonFrame];
I usually go for -release rather than -autorelease whenever possible. This comes from years of experience debugging and enhancing other people's Objective-C code. Code that uses autorelease everywhere makes it harder to debug when an object gets over-released, since the extra release happens far away from the incorrect code.
It's also the case that many folks use autorelease when they just don't understand how cocoa memory management works. Learn the rules, learn the API, and you'll almost never need to autorelease an object.
A last minor point is that if you don't need the autorelease behavior, then using autorelease just needlessly adds extra work for your program to do.

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!!!