__weak IBOutlet ivars need release and/or bad practice? - ios

I am using XCode 5.1.1, targeting iOS 7.0.
When creating outlets from my storyboard using the Assistant editor. I notice I have a few choices to create properties or ivars. The one I have been using is dragging directly to my *.m #implementation and it creates code like:
#implementation AudioViewController
{
__weak IBOutlet UILabel *posLabel;
__weak IBOutlet UILabel *durationLabel;
__weak IBOutlet UIButton *playButton;
}
I have no need to access these outside of this class, so this seems convenient, but I am wondering if there are any "gotchas" to this method vs creating properties, especially in regards to memory management. I read on other stack answers that you must create (weak) properties or I will have to [release] manually. I am wondering if this __weak takes care of that in this context?
Thanks!

Creating properties and instance variables with the same modifier is mostly analogous. When you are using ARC, you do not have to release strong properties or instance variables - they will be released when the object is deallocated. Interface element outlets are usually created as weak, because they are retained by the view hierarchy. You should be careful; if you intend to remove the elements from the view hierarchy at some point, you should change the modifier to strong to ensure they are retained by the view controller. Top-level outlets should also be created as strong to make sure they are retained after nib load.

Related

IBOutlet why always weak and object of array ,dictionary etc are need to be strong

i am new in ios programming , i just want to know why we use IBoutlet of every controller to be weak and other Need to strong
can we define IBoutlet to be strong ?
if yes then what is difference ?
It has to do with ownership of the variable, since most IBOutlets are sub views of you view the ownership of the view lies with the view.
If you are creating your own properties you will need to retain the variable thus you make the property strong.

Weak references and Retain cycles

I'm developing an application that using ARC,so I have 3 cases:
1 #property (strong, nonatomic) IBOutlet UILabel *titleLabel;
That means: titleLable has a strong references to superView and superView has a strong references to titleLabel?
2 #property (weak, nonatomic) IBOutlet UILabel *titleLabel;
That means: titleLable has a weak references to superView and superView has a strong references to titleLabel?
3 I declare:
UILabel *titleLabel = [[UILabel alloc] initWithFrame:self.view.bounds];
[self.view addSubview:titleLabel]
Could everyone answer my questions?
My description for case 1 and 2 are correct?
In case 1, can the superView release or not? because i think titleLable has a strong reference to supperView
In case 3, why we dont need declare __weak for titleLabel, maybe superView can be release in this case?
Thanks for your responses.
The other answers here are good, but I want to be extra clear about a misconception you seem to have. Properties on classes are one-way relationships, not two.
So you ask in each case about how that property references its owner (strong or weak) but the reality is that it doesn't reference it at all. In fact no object has any knowledge of what other objects own it at any given time. The only thing that it tracks is how many objects own it. If you want a two way relationship where both objects have a reference to each other, that is when you need a weak reference in at least one direction. Otherwise, both object are making sure the other never gets dealloced and therefore neither will ever be dealloced. That is what is called a "circular reference". It can happen between more than two objects as well where A has a strong reference to B, B has a strong reference to C, and C has a strong reference to A.
Now, regarding the "superview" method on UIViews. This will always be a weak reference and is setup automatically when you add a subview. This is because the parent view always has a strong reference to all of its children. If a child ever had a strong reference to its parent, there would be a circular reference. But please note, that adding a property to a view, does not automatically add it as a subview, that must still be done manually in code or inside a xib or storyboard.
So in short, only case 3 creates reference between the view and the label because you added it as a subview. Then self.view has a strong reference to the label. As a completely different mechanism, the view then adds a weak reference to itself on the subview called "superview".
I'm going to assume titleLabel is a property in a UIViewController.
1.1 - UIViewController has a strong reference to titleLabel. titleLabel has no reference to UIViewController.
2.2 - UIViewController has a weak reference to titleLabel. titleLabel has no reference to UIViewController. titleLabel will only be retained if you have strong reference to it somewhere. Adding it to the view hierarchy counts as a strong reference.
3.3 - In this case UIViewController has a strong reference to titleLabel until it goes out of scope. However, you add it to the view hierarchy which will retain it until its superview leaves the view hierarchy.
To clarify best practice re IBOutlet references, as the Resource Programming Guide: Nib Files document says:
Each time you ask the NSBundle or NSNib class to load a nib file, the underlying code creates a new copy of the objects in that file and returns them to you. (The nib-loading code does not recycle nib file objects from a previous load attempt.) You need to ensure that you maintain the new object graph as long as necessary, and disown it when you are finished with it. You typically need strong references to top-level objects to ensure that they are not deallocated; you don’t need strong references to objects lower down in the graph because they’re owned by their parents, and you should minimize the risk of creating strong reference cycles.
From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create should therefore typically be weak, because:
Outlets that you create to subviews of a view controller’s view or a window controller’s window, for example, are arbitrary references between objects that do not imply ownership.
The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).
And note while this only has one parenthetical reference to storyboards, most of this discussion applies equally well to storyboards as to NIBs.
So, if your label is an IBOutlet that you've hooked up in Interface Builder, use weak.
If you perform an addSubview of a manually instantiated label, that addSubview will ensure that the view maintains a strong reference to the label for you (until such point that you remove it from its superview, or that view, itself, is deallocated), so you don't need to maintain any additional strong references to it, nor do you need to worry about it being released when the local variable falls out of scope.
In case 1, your object (presumably a view controller) has a strong reference to titleLabel. The declaration of the property does not tell us anything about the reference held to titleLabel by the label's superView (which is presumably self.view, not self). You could presume that self.view is a strong reference and you would assume that the view would retain a strong reference to its subviews - of which titleLabel is one - and that titleLabel would retain a weak reference to its super view.
In case 2 your object has a weak reference to titleLabel. This does not change the way in which your object holds a reference to its view nor how that view holds a reference to its sub views nor how titleLabel holds a reference to its super view.
In case 3 a weak reference will work because there are enough references being held through the view hierarchy to prevent titleLabel from being release prematurely.
In all cases the release of objects will be handled through the view controller lifetime methods that ensure that the view and its subviews are removed recursively when the view controller is removed

programatiically creating views strong properties

Previously I've been creating my views with interface builder.
When creating views with storyboards or nibs I would connect my outlets. I understand that the outlets are creating a strong connection to the properties on the view.
If I am creating views programmatically should my properties be strong?
.h
#interface LoginViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, strong) UIView *loginView;
#property (nonatomic, strong) UITextField *usernameTextField;
#property (nonatomic, strong) UITextField *passwordTextField;
#property (nonatomic, strong) UIButton *signInButton;
#end
.m
#interface LoginViewController ()
#end
#implementation LoginViewController
- (void)initViewsAndLayout
{
_loginView = [[UIView alloc] init];
_loginView.frame = self.view.bounds;
[self.view addSubview:_loginView];
//...
}
#end
A few things:
Your code isn't using the properties you defined
Don't put the private properties in the .h file
Don't state that your class conforms to the UITextFieldDelegate protocol in the .h file
As for whether the properties should be strong or weak I prefer strong but since you will be adding each of these properties (views) to the view controller's view, it would be fine to make them weak since there will always be a reference to them as long as the view controller is alive.
Your .h should just be:
#interface LoginViewController : UIViewController
#end
Your .m should be (assuming you do want to use the properties):
#interface LoginViewController () <UITextFieldDelegate>
#property (nonatomic, strong) UIView *loginView;
#property (nonatomic, strong) UITextField *usernameTextField;
#property (nonatomic, strong) UITextField *passwordTextField;
#property (nonatomic, strong) UIButton *signInButton;
#end
#implementation LoginViewController
- (void)initViewsAndLayout
{
self.loginView = [[UIView alloc] init];
self.loginView.frame = self.view.bounds;
[self.view addSubview:self.loginView];
//...
}
#end
When you use the strong attribute, you are basically writing retain, as in, you want Objective-C to allocate memory for the property and hold it until it is released.
That is all strong means.
This is only necessary if you are using ARC (though you can still use retain in ARC). If not, use retain.
"If I am creating views programmatically should my properties be strong?"
If they are objects and not primitives, then yes.
I recommend you to make properties with strong attribute if you want to create it manually not to use xib or storyboard.
As your code in initViewsAndLayout, if you always create a subview and add it to a view of a viewcontroller simultaneously in same method scope, there is no problem even if you use weak or assign attribute. addSubview will increase a reference count of the subview. But, I don't think it's such a good habit because all of us could make a mistake.
Therefore, you had better make a property of UIView with strong attribute.
You asked:
If I am creating views programmatically should my properties be strong?
Two part answer:
The view controller should definite maintain a strong reference to its top level view.
When not using NIBs or storyboards at all and doing everything programmatically, the root view is instantiated in loadView and generally stored in a retain/strong property. UIViewController already has a view property that bears the retain memory semantics, thats generally used. (For more information about programmatically created views, see the Creating a View Programmatically section in the Resource Management in View Controllers chapter of the View Controller Programming Guide for iOS)
(If you're not creating the root view in loadView and are instead instantiating the root view with a NIB or storyboard and are only programmatically creating the subviews, don't worry about the above discussion, as the NIB/storyboard takes care of all of that for you.)
For the subviews, when you call addSubview, the view is retained by its parent view. It's unnecessary for the view controller to also maintain strong reference to it as well. You can, but it is not necessary.
In my mind, the view owns its subviews, not the view controller. If one of these subviews is removed from its parent view, I don't think the view controller should be retaining it and it doesn't seem like good design that I have to remember to nil the property in the view controller, too. Worse, if I remove a container view that has nested subviews, I don't want to have to manually keep track of setting all of those individual properties in the view controller that I have to nil, as well.
Don't get me wrong: You can use strong with the subviews if you want/need. But I think it's incorrect to imply that it's ill-advised to use weak.
As a simple rule of thumb,
Any view is always owned (maintained by strong reference) by its
superview, when they are added to the superview.
A top-level view is always owned (maintained by strong reference) by its VC.
Now, a view can be added to its superview in two different ways,
When a view is created from code and added to some superview using addSubview: method. (This is what your question suggest).
When the view hierarchy is loaded from a nib file. (Here also implicit addSubview: calls are made by UIKit to create the hierarchy) and thus subviews are retained by strong reference their respective superviews.
So in either cases views are implicitly retained by their superviews and thus never get disposed until/unless the top-level view gets disposed by itself. So declaring strong properties for subviews imposes another ownership on the subviews:
An implicit ownership by its superview, and
An explicitly ownership by the property.
So in general, declaring strong property for subviews are not required, however it has been created (from nib / by code).
However, under some special situation declaring strong properties for views might be required. For example, when a view should be removed and re-added to its superview, the view should be declared as strong. When such a view is removed from its superview, the superview releases its ownership as well. So if we need to maintain a strong reference of that view if we need to reassign the same view again to some superview. In that case, a strong property reference to the view becomes handy and it disallows the view to be released.
PS:
When creating views with storyboards or nibs I would connect my
outlets. I understand that the outlets are creating a strong
connection to the properties on the view.
I found that there's merely a misconception, in your question. When creating view from storyboard/nib, outlets does not create any so-called strong connection with the properties. IBOutlets only describe how a property loads a view. In case of an outlet property, the view pointed by the property is unarchived and loaded if it has not already been loaded. However, its retention still depends on the strong/weak property accessor.

Creating IBOutlets as ivars on ARC. Memory issues?

I'm aware best practices for Objective-C development says IBOutlets should always be defined as properties according to Apple.
From a practical perspective, in iOS and OS X outlets should be
defined as declared properties. Outlets should generally be weak,
except for those from File’s Owner to top-level objects in a nib file
(or, in iOS, a storyboard scene) which should be strong.
But for learning purposes let's say we got the following scenario using ARC:
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController{
IBOutlet UIButton *buttonA;
IBOutlet UIButton *buttonB;
IBOutlet UIButton *buttonC;
}
#end
If I'm not mistaken, those three buttons are strong, so my question is: Will those buttons be released from memory once the ViewController is released?
Those buttons would be released automatically if they were weak, I know that, but not sure if they are strong.
Can anyone please help? Just to be clear, the method 'dealloc' on DetailViewController is empty.
You asked:
If I'm not mistaken, those three buttons are strong, so my question is: Will those buttons be released from memory once the ViewController is released?
Yes. Or, more accurately, those buttons will be deallocated when there are no more strong references. And in this scenario, those buttons now have two strong references, one being the view controller and another being the view to which these buttons were added as subviews. Both of those strong references would need to be relieved before the button would be deallocated.
But why would you want to maintain two strong references to that control? Generally you let the view maintain the strong reference to its subviews (i.e. let the view "own" its subviews), and the view controller is only using a weak reference to those subviews.
Those buttons would be released automatically if they were weak, I know that, but not sure if they are strong.
When the view controller has the weak reference, the buttons are being released because the only strong reference to the button is maintained by its superview and when that view is removed, then the button will lose its last strong reference and can be deallocated.
If the view controller has a strong reference, you are unnecessarily added another strong reference that needs to be relieved before the buttons are deallocated. You can do that, but it's unnecessary. You quoted from the Resource Programming Guide, but the preceding sentence says "you don’t need strong references to objects lower down in the graph because they're owned by their parents, and you should minimize the risk of creating strong reference cycles."
Bottom line, your example with the implicitly strong references to the IBOutlet controls will work fine. But there's no advantage to having the view controller maintain a strong reference to the buttons and it represents a bit of a misunderstanding of the object graph. View controllers really should only be maintaining weak references to the controls on their views.
Yes, when the ViewController is released, even its strongly referenced objects will be released. (Unless of course, some other non-released object holds a strong reference to them.)
There's a good discussion of weak and strong here: Explanation of strong and weak storage in iOS5

ios UIViewController not calling viewDidUnload

When I simulate a memory warning, viewDidUnload should run on unused objects, right?
How do I go about figuring out WHY my UIView won't go away?
FYI I'm using ARC and every ivar is an IBOutlet and looks like:
#property (nonatomic, weak) IBOutlet UIView *someView;
What class are we looking at here? Only UIViewControllers release their view in case of a mem warning.
If this is a custom class or a custom added view, you should unload it yourself.

Resources