I have developed application using ARC. In one of my UIViewController there are number of sub controllers (Like Buttons, Labels, Textfields, Textview, Scrollview) which all are having its IBOutlet. Here issue is that,I am using iOS 6.0.
With iOS 6.0 viewDidUnload method is deprecated. So at the time of Pop, this method is not called. I have checked with "product--> profile--> allocation" here whenever this controller is pushed in the navigation stack it increases the live memory Bytes but on pop Memory bytes don't decrease. Because of this after using an application for some time I am getting Received Memory Warning & application is going to be crashed in random instances.
Is there any alternative way to handle this kind of backend memory management issue.
First check in .h file that you property-sythesized with retain or not if with retain then set strong instead of retain like bellow..
#property ( nonatomic, strong) IBOutlet UITextField *yourTextField;;
Related
One of my UIViewController has several child view controllers. They are built inside the interface builder, by dragging an NSObject to the "Objects" section at left, then put in my own SpecialViewController as "Custom Class". With this setup, upon viewDidLoad I'll have my views and the controller ready. The workflow is suggested by the following screenshot:
And in my implementation, I have:
#interface ParentController : UIViewController
{
SpecialViewController *svc;
}
#property (nonatomic, retain) IBOutlet SpecialViewController *svc;
As I understand that during didReceiveMemoryWarning I should release my own resources. Then set IBOutlets to nil during viewDidUnload.
I get crashes when simulating low memory in the simulator, with debugger pausing at didReceiveMemoryWarning of SpecialViewController (whose body is just [super didReceiveMemoryWarning];), with error EXC_BAD_ACCESS (code=1, address=0xe0000008). At this time, the parent controller isn't visible, so it can be safely released.
Parent controller also contains only [super didReceiveMemoryWarning]; in didReceiveMemoryWarning. I've tried niling IBOutlets in both classes. It didn't help.
Any idea why this happened?
I'm targeting iOS 4 & 5 with ARC. SpecialViewController is a subclass of UITableViewController.
Through tracing, I found that ParentController didReceiveMemoryWarning is called before SpecialViewController.
It seems like you have a view controller with in a view controller here. Is there any particular reason that you have chosen to create the class like this? In my experience each UIViewController should be a separate subclass. Based on the fact that your error arises in didReceiveMemoryWarning, I believe that the issue is elsewhere. Can you share your initialization code for this View Controller?
If you are attempting something like UIViewController Containment, you should probably check out the WWDC topic that covers this process.
Update iOS > 6.0:
Views are no longer purged under low-memory conditions and so this method is never called [1].
View controller's didReceiveMemoryWarning default implementation will release their view; your responsibility is only to release any other views created in viewDidLoad or loadView, as well as any strong references to IBOutlet subviews.
You have a strong reference to another view controller, which will not be recreated when the view becomes visible again. You should not use the didReceiveMemoryWarning to release your the sec instance variable; instead, rely on the SpecialViewController's didReceiveMemoryWarning implementation to take care of releasing it's view.
In practice, I use didReceiveMemoryWarning to release my main view (self.view) and use viewDidUnload to release anything created in viewDidLoad. I find the balance of the names of the methods and their uses intuitive. If you create something in viewDidLoad, release it in viewDidUnload.
My app is nearly finished and I have been Profiling it using Instruments. I'm checking out retain counts of various objects.
I have been careful to release any objects which I have called alloc on, and these don't seem to be leaking - so thats cool.
However, I have a view controller which has a UIPickerView in it. I set that up by dragging it onto my NIB in IB, defined the property using IBOutlet, synthesized it, and then hooked it all up.
Every time I launch the view, it seems the number of UIPickerViews increases by one. I was under the assumption that I do not need to release this kind of thing myself, as I had assigned it to a property (using nonatomic, retain).
This is happening to all my UI stuff - buttons etc, not just the picker view. I was just using that as an example.
Can anyone help me out here?
Thanks!
When the view is loaded all the items created from the NIB are retained for you and your IBOutlet pointers are initialized pointing to those retained subview objects. You need to release those in viewDidUnload. Are you doing that?
In viewDidUnload you should release all objects created from the NIB and set those pointer to nil. You should also release those same object in dealloc. Example here.
I encountered a weird behavior in memory just by displaying the default keyboard.
I've just created a project with an .xib file for testing purposes.
This .xib file has an UITextField element in it and it's connected in the .h via:
#property(nonatomic, retain) IBOutlet UITextField *sometext;
The .m has no changes but:
#synthesize sometext;
- (void)viewDidAppear:(BOOL)animated {
[someText becomeFirstResponder];
}
As you see it's very very simple.
The problem is that once the keyboard is shown, the memory allocated for it NEVER goes down.
I've tested this scenario in another project with the only difference of having two .xib files.
Standar pushViewController and popViewController calls are made. Instruments show an increase of 600kb in memory allocations [which are a lot more in the actual iPhone device].
All in all, hehehe. My question is:
How do I release the memory allocated for the keyboard?.
You don't. Is it a leak? If you are just looking at the Allocations, don't expect it to go back down.
EDIT:
Clarification - Object Allocations in Instruments will always go up. It won't go down. It doesn't show deallocations, just allocations...
I am using #property(nonatomic, retain) for my IBOutlets for an iPhone application. However, I'm not sure how to make sure I'm managing memory with them properly. The IBOutlets are all set up in Interface Builder, so I'm never calling alloc manually. This means that I'm not sure when and if to deallocate them or when to set them to point to nil.
What are the best practices ensuring that no memory is leaked once the view unloads?
If you use #properties for yourIBOutlets and make the connections in IB then your controller is essentially retaining the IB objedcts with the property and is it therefore responsible for releasing them when it's done with them.
When are you done with them?
In every case you should be setting your properties self.propertyname = nil in your viewDidUnload method and again in dealloc of each viewController.
It's quite straight forward, IB manages everything else.
By default, the semantics of #property is retain, meaning that when the view controller loads the nib and connects IBOutlets, they get retaind by the #synthesized setter. Follow the standard rules of Cocoa memory managment: you must release these properties eventually or you will leak memory. dealloc is probably a good place to do this. On the iphone you can do this via self.outletProperty = nil. On OS X (when you're not using GC), the rules are the same, except you can use [self->outletProperty release] explicitly, bypassing the #synthesized setter.
You should do it like this....
[yourOutletVar release];
yourOutletVar = nil;
Please don't forget to set the IBOutlets to nil finally, because it is necessary to get rid of dangling pointers issue.
In most examples I see the following setup of IBOutlets:
(Example A)
FooController.h:
#interface FooController : UIViewController {
UILabel *fooLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *fooLabel;
#end
FooController.m:
#implementation FooController
#synthesize fooLabel;
#end
But this works also fine (notice: no property and no synthesize):
(Example B)
FooController.h:
#interface FooController : UIViewController {
IBOutlet UILabel *fooLabel;
}
#end
FooController.m:
#implementation FooController
#end
Are there any downsides of defining IBOutlets as in Example B? Like memory leaks? Seems to work fine and I prefer to not expose the IBOutlets as public properties as they are not used as such, they are only used in the controller implementation. Defining it in three places without a real need does not strike me as very DRY (Don't Repeat Yourself).
On Mac OS X, IBOutlets are connected like this:
Look for a method called set<OutletName>:. If it exists call it.
If no method exists, look for an instance variable named <OutletName>, set it without retaining.
On iPhone OS, IBOutlets are connected like this:
call [object setValue:outletValue forKey:#"<OutletName>"]
The behavior of set value for key is to do something like this:
Look for a method called set<OutletName>:. If it exists call it.
If no method exists, look for an instance variable named <OutletName>, set it and retain it.
If you use a property, you'll fall into the "Look for a method called set<OutletName>:..." case on both platforms. If you just use an instance variable, then you'll have different retain/release behavior on Mac OS X VS iPhone OS. There's nothing wrong with using an instance variable, you just need to deal with this difference in behavior as you switch between platforms.
Here's a link to full documentation on just this topic.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6
On Mac OS X, IBOutlets are not retained by defaults. This is the opposite of the behavior on iPhone OS: on iPhone OS, if you don't declare a property it is retained and you must release this property in the dealloc method. Additionally, the 64-bit runtime can synthesize instance variables using property declarations. That means that someday the instance variables (with the IBOutlet) may be omitted.
For these reasons it is more homogeneous and compatible to create always a property and use the IBOutlet only in the property. Unfortunately, it is also more verbose.
In your first example you always have to release the outlet in the dealloc method. In your second example you must release the outlet only with iPhone OS.
The end result is exactly the same, but you have to keep a few things in mind:
When using instance fields as outlets, you should NOT release them in dealloc.
When using properties that have the (retain) attribute, you have to release the property in dealloc (using self.property=nil or by releasing the backing variable). This makes it a lot more transparent as to what's going on.
Actually it all comes down to the same old rule: "thou shalt release what you alloc/retain". So in case you use an instance field as outlet, you didn't alloc/retain it, so you shouldn't release it.
Its possible that those examples use the retain because the sample code is programmatically allocating and initializing a UILabel and then adding it to the UIView. That's the case for many examples, since learning how to use Interface Builder is often not their point.
The second example (no property and no synthesize) with the IBOutlet is used when the developer 'assigns' the UILabel (Button, View, etc) within the Interface Builder -- by dragging the IBOulet to the Label or other View component. In my opinion, the preceding drag and drop action (Label onto View) also add the subview, the Label to a View -- and so on. Label is retained by a View; a View is retained by Window; Window is retained by File's Owner. File's Owner is usually your Document that is booted up in main.
You will note that when you step through your program (by adding an awakeFromNib
- (void)awakeFromNib
{
[fooLabel blahblah];
}
that fooLabel already has a memory address.
Thats because the Label was initialized from a file bundle (the nib file) using not init but initWithCoder. Which essentially deserializes the filestream to an object - and then sets the IBOutlet variable. (We're still talking about the IBOutlet method).
Also note that the aforementioned iOS method uses the Key Value method
call [object setValue:outletValue forKey:#"<OutletName>"]
which is the Observer/Observable pattern. That pattern require the Observable object reference each Observer in a Set/Array. A change in value will iterate the Set/Array and equally update all Observers. That Set WILL already retain each Observer thus the lack of retain in iOS.
Further and the rest is speculation.
It seems that cases when you do use Interface Builder then
#property (nonatomic, retain) IBOutlet UILabel *fooLabel;
should possibly be changed to
#property (nonatomic, weak) IBOutlet UILabel *fooLabel;
or
#property (nonatomic, assign) IBOutlet UILabel *fooLabel;
And then it needn't be released in a dealloc method. Plus it will satisfy the OSX and iOS requirements.
That's based on logic and I could be missing some pieces here.
Nevertheless, it may not matter if the view is persistent through the life of your program. Whereas a label in a modal dialog box (open, close, open, close) may in fact have over-retained and leak per cycle. And that's because (speculation again) each closed dialog box is serialized into a file system and thus persists x,y position and size, along with its subviews, etc. And subsequently deserialized ... on the next session open (Opposed to say minimiz or hidden.)