Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strong and weak modifiers with ios interface elements

in my projects I don't use Interface Builder and I've noticed one thing that I don't know how to explain. Yet. So, to the point. When we are using IB and defining elements of user interface like UILabel or UIButton in our controller we use this ugly prefix IBOutlet and a 'weak' modifier. This works like music. But when we decide not to use IB and define whole user interface from code it just doesn't work.

Let's assume that I want to add UILabel to controller (using IB). I will have something like this i *.h file:

@property (nonatomic, weak) IBOutlet UILabel * label;

And I don't have to do anything more in *.m file. But if I remove the *.xib file and try to setup my UILabel in, for example, one of init methods, like this:

self.label = [[UILabel alloc] initWithFrame:CGRectMake(0,0,100,20)];
self.label.text = @"some text";
[self.view addSubview:self.label];

It doesn't work until I alter my *.h file to this:

@property (nonatomic, strong) UILabel * label;

Now, I know the difference between weak and strong but I have no idea why we can use weak for ui elements when using IB? Something must keep a strong pointers to these elements, right? But what?? In second case it is controller, but I don't understand how it behaves in the first case.

like image 267
pawel.kalisz Avatar asked Feb 07 '13 21:02

pawel.kalisz


3 Answers

The reason why Interface Builder creates weak references for IBOutlets is as follows:

IB knows that a view is retained by its superview. So any object in the tree of views there's no need to have strong references other than to the root object. The view controller keeps this strong reference in its main view property.

Now when the view in unloaded (at least until iOS 5), the UIViewController's view property is set to nil, releasing the main view. If the IBOutlets to subviews of this superview would be strong references they would keep part of the view hierarchy in memory. That's unwanted (and could possibly lead to confusion when accessing these orphaned views).

like image 81
Nikolai Ruhe Avatar answered Nov 18 '22 12:11

Nikolai Ruhe


Something must keep a strong pointers to these elements, right? But what??

Correct, you must have at least 1 strong reference to an object for it to exist. You'll only need to have a strong reference to the root level objects of the UI, anything below this can be weak (as the parent objects will own their children). The .xib file in co-ordination with its Files Owner would have done this for you.

See this document on the workings of xib files. Specifically, this snippit:

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

like image 41
WDUK Avatar answered Nov 18 '22 14:11

WDUK


Despite of accepted answer, this is how you can make it in code:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0,0,100,20)]; // strong ref
label.text = @"some text";
[self.view addSubview:label]; // strong ref from superview
self.label = label; // weak ref
// Now you can do `label = nil;`

This is the point when loading from XIB. The label already has superview when it is assigned to your weak property.

like image 44
Tricertops Avatar answered Nov 18 '22 13:11

Tricertops