I have some doubt regarding retain in .h file. I know that if we alloc/copy/retain than we need to release it, but in following case
#property (nonatomic, retain) IBOutlet UITableView *myTable;
Do I need to release this table view object in my dealloc. I have created this tableview using xib.
Thanks.
So sayeth the docs:
Objects in the nib file are created with a retain count of 1 and then
autoreleased. As it rebuilds the object hierarchy, however, UIKit
reestablishes connections between the objects using the
setValue:forKey: method, which uses the available setter method or
retains the object by default if no setter method is available. If you
define outlets for nib-file objects, you should always define a setter
method (or declared property) for accessing that outlet. Setter
methods for outlets should retain their values, and setter methods for
outlets containing top-level objects must retain their values to
prevent them from being deallocated.
And:
When a low-memory warning occurs, the UIViewController class purges
its views if it knows it can reload or recreate them again later. If
this happens, it also calls the viewDidUnload method to give your code
a chance to relinquish ownership of any objects that are associated
with your view hierarchy, including objects loaded with the nib file,
objects created in your viewDidLoad method, and objects created lazily
at runtime and added to the view hierarchy. Typically, if your view
controller contains outlets (properties or raw variables that contain
the IBOutlet keyword), you should use the viewDidUnload method to
relinquish ownership of those outlets or any other view-related data
that you no longer need.
So basically, when being loaded from a NIB/XIB, the property is used. Meaning, if you specify retain properties on your IBOutlets (which you should), you need to release them. The preferred way to do this is in viewDidUnload, using the property.
#property (nonatomic, retain) IBOutlet UITableView *myTable;
...
- (void) viewDidUnload
{
self.myTable = nil;
}
Yes you will have to as you would be creating an object in the .h file and allocating it memory.. The only thing you are doing in XIB is creating a link between the two (XIB just acts as an outlet for the inner tableview) , but if you posted a button using the xib and did not link it via the code then you don't have to release it...
First of all you are not retaining anything in .h file.
The purpose of #property declaration in the .h file (it can also be don in .m file) is to tell the compiler how to handle the getters and setters for this property when you use (dot syntax).
Example:
Declaring property in the following way:
#property (nonatomic, retain) IBOutlet UITableView *myTable;
Tells the compiler that when you create a UITableView in your .m file like so:
- (id)initWithTable:(UITableView *)table
{
self = [super init];
if (self) {
self.myTable = table;
}
return self;
}
Compiler will automatically know to retain it, and so you would also need to release it.
But if you would declare your property in the following way:
#property (nonatomic, assign) IBOutlet UITableView *myTable;
and created the tableView as in the previous example
- (id)initWithTable:(UITableView *)table
{
self = [super init];
if (self) {
self.myTable = table;
}
return self;
}
The compiler would only assing the value of myTable to point to table. You would not own it and should not release it.
No u dont need to
u only need to release object which you have allocated.
since the table view is allocate in the xib it's release should be none of your concern
hope this helps
it should be release. if you want to see difference then run your application in instruments and check it.
Related
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...
In looking at one of Apple's examples, in the TableViewController.m, they have this:
// Private TableViewController properties and methods.
#interface TableViewController ()
#property (nonatomic, retain) NSMutableArray* sectionInfoArray;
#property (nonatomic, retain) NSIndexPath* pinchedIndexPath;
#property (nonatomic, assign) NSInteger openSectionIndex;
#property (nonatomic, assign) CGFloat initialPinchHeight;
... more properties and methods
#end
#implementation TableViewController
... usual stuff
I'm wondering why they put these properties in the .m file and how this is private. It seems like anyone who imports the TableViewController.m file can use these properties and methods right? Why not use the #private in the .h file?
What they're doing is declaring a category on the class, but since this is done in the .m file, the effect is that those methods are "invisible".
This doesn't mean however that those methods cannot be called from the outside. This is due to the fact that there is no real privacy in objective c, because we're dealing with messages, not method calls. This means you can send an object a message even if you do not know if that object actually implements the method you're trying to call. The receiving object will determine at runtime if it can handle this call, maybe it will even forward it, and it will make no difference whether the method was known to the calling object or not.
This is one of the reasons why it is possible to call private APIs and get rejected for it.
They're not private. They're anonymous properties, since they're part of an anonymous category.
One of the things properties are good for is putting the memory management semantics for an owned object in a single place. Consider this:
#property (nonatomic, assigned) NSString *assigned;
#property (nonatomic, copy) NSString *copied;
#property (nonatomic, retain) NSString *retained;
In all three cases, you can assign to them like this without knowing what their memory semantic is:
self.assigned = stringParameter; // assigns to instance variable
self.copied = stringParameter; // copies, assigns copy to instance variable
self.retained = stringParameter; // retains, assigns to instance variable
And in all three cases, you can free clean up using the same code:
self.assigned = nil; // this just nils the instance variable
self.copied = nil; // releases copy in ivar, nils instance variable
self.retained = nil; // releases ivar (same as original object),
// nils instance variable
This is why you'll often see local properties: It lets the coder skip writing all the memory management logic each time they want to assign to the instance variable. This is a major advantage in that you can change the memory management logic throughout the entire class just by changing the #property.
Another use of anonymous properties is to extend a property declared as readonly to outside code as read/write to the class itself.
In .h:
#property (nonatomic, readonly, retain) NSError *lastError;
In .m, in an anonymous category:
#property (nonatomic, readwrite, retain) NSError *lastError;
Elsewhere in .m code:
self.lastError = error;
Again, this is mostly done for memory management reasons.
An example, that pertains to either use of anonymous properties.
Here's what each assignment to a _lastError instance variable looks like without properties.
Assume we have a NSError called _lastError defined in the .h file.
With retain:
[_lastError release];
_lastError = [error retain];
With copy:
[_lastError release];
_lastError = [error copy];
With assign:
_lastError = error;
In the first two cases, you need this in your dealloc:
[_lastError release];
But in the last case, you must put nothing in the dealloc or you'll get a crash.
So let's add what we need to use a property instead:
Add this in an anonymous category:
#property (nonatomic, readwrite, retain) NSError *lastError;
Add this in the #implementation:
#synthesize lastError = _lastError;
Note, also, that at this point on the "modern" Cocoa runtime (64 bit Mac or iOS), you can remove the NSError *_lastError from your header. The compiler can figure out you want that based on the #synthesize.
Here's how that changes our code:
Each assignment:
self.lastError = error; // works regardless of storage specifier
In daelloc:
self.lastError = nil; // works regardless of storage specifier
AFAIK
a) You can not mark properties as #private in .h - this works only for ivars.
b) You will not be able to reference your class if you just import .m file (without interface definition in .h file). and if you do - you will get duplicate symbols during linking.
c) So yes these properties are private in the sense they are not accessible as regular properties from outside - these properties are accessible only using explicit messages - however you'll get warnings from compiler in this case or you could use KVC
First, you typically cannot import an .m file - not without numerous compiler/linker errors. Second, the properties are private so that Apple is free to change them in subsequent releases.
Yes, you can get to them via reflection. But that's a slippery slope, blah blah proceed at your own risk, will break in later versions blah blah reflection bad unless you know exactly what you're doing.
There are no private methods or variables in objective c, the #private flag is mainly there just so when other developers look at it, they know it's supposed to be private. What your seeing in the apple code is an example of a category, a way to fake private methods and variables in objective c. Because outside classes will import the .h file only, they will never see the added methods and variables in the .m file.
Using an anonymous category black boxes internal properties and methods that other classes should not know about. Although the compiler doesn't know about them when this class is referenced from other classes, you could technically access any of these properties from that other class using key value coding.
you can't import the implementation file TableViewController.m, Only the .h file of TableViewController could be imported,
Although, you could have the reference of these property outside your TableViewController class with a warning that shows the "not respond" note.
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...
Let's say I have a simple view controller with one UITableView property:
#interface MyViewController : UIViewController {
UITableView *tv; // <-- DO I NEED THIS??
}
#property (nonatomic, retain) IBOutlet UITableView *tv;
#end
Do I actually need to declare the UITableView *tv ? I've found that even if I don't declare it (and simply #synthesize the property), everything works fine. Yet, lots of code samples explicitly declare the variable. I'm not sure what the benefit of declaring it (or the harm of not declaring it) is.
In Objective-C 2.0, the compiler will synthesize the storage for you as well as the accessors. That didn't used to be the case, hence all the examples where people explicitly declare the ivar.
No you do not have to declare it, synthesize will take care of dynamically injecting the code at compile time. You will on the other hand not be able to inspect the variable directly in Xcode if you do not declare it, that's the downside.
I have a .xib file containing a UIView and 2 UILabel subviews linked to a class named Note with outlets assigned to each label appropriately, the definition for this class contains the following.
#interface Note : UIView {
IBOutlet UILabel *time;
IBOutlet UILabel *content;
}
I'm constructing this with the following code
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:#"Note" owner:self options:nil];
note = [nibViews lastObject];
[self addSubview:note];
Now, in my Note class dealloc phase, I'm not releasing either time or content, but I'm wondering if I should?
- (void)dealloc {
[super dealloc];
}
I'm assuming I don't because I'm not explicitly retaining these objects anywhere in my code, and I don't synthesize these into getter/setters. But I don't know enough about nib unarchiving to know whether I should be releasing these in my dealloc phase or not?
You should release an IBOutlet even if you're not writing or synthesizing accessor methods. The NIB lifecycle documentation says that although unarchived objects are initially set to autorelease, the retain count on them is bumped up by an extra 1 when UIKit hooks up all the IBOutlet connection bindings. You therefore need to manually decrement via release when you're done.
It's not obvious that UIKit would be doing this so you might assume you can just leave the setter/getter methods off and trust that everything is autoreleased. But that's not the case.
Notice that Interface Builder templates explicitly release any IBOutlets, so any you add should be treated likewise.
This is correct for the iPhone; it would not be correct on the Mac, though.
However, you may want to rework this code. It isn't safe to assume that the view will be the last object loaded from the nib. I'd suggest instead that you either connect it to a "note" outlet in your view controller or scan the list for an object that's a subclass of Note. (If you're loading multiple Notes and you use the outlet option, just make sure you add one Note before loading another.)
You DO need to release it. See
"As it rebuilds the object hierarchy, however, UIKit reestablishes connections between the objects using the setValue:forKey: method, which uses the available setter method or retains the object by default if no setter method is available." in Nib Object Retention
In other words, because you haven't specified these entries as #property (which implicitly declares a setter), or provided a setter directly, there is no available setter method, and the final part of this paragraph applies - the object is retained by default.
You should, in your dealloc() method, set all IBOutlets to nil using
self.outletName = nil;
If no setter is defined, then setValue will autorelease the old value (make sure you have an NSAutoreleasePool if running in a thread). If a setter is defined, it will perform whatever behaviour you defined. Either way, the set to nil will do exactly the right thing, and ensure you get no memory leaks. Do NOT do this
outletName = nil;
This will directly set the member variable, and bypass calling setValue.
See the documentation of NSObject setValue:forKey for more details.
Running the Performance Tool (Leaks) will not show a leak, but you can verify that there is actually a leak by looking at the current running total of allocated memory.
cf The Airsource - Memory Management and NIBs
You will not be able to take them out of memory unless you declare the IBOutlets as properties and synthesize them to ivars:
#interface Note : UIView {
IBOutlet UILabel *time;
IBOutlet UILabel *content;
}
#property (nonatomic, retain) IBOutlet UILabel *time;
#property (nonatomic, retain) IBOutlet UILabel *content;
#end
#implementation Note
#synthesize time, content;
// your methods
- (void)dealloc {
[time release], time = nil;
[content release], content = nil;
[super dealloc];
}
#end
I belive you are correct. See the documentation links below for more details.
Documentation:
The Nib Object Lifesycle
Dicussion Thread at Apple support boards
Another discussion thread