Strong and weak modifiers with ios interface elements
Asked Answered
D

3

7

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.

Drover answered 7/2, 2013 at 21:47 Comment(4)
I don't know either why would/could/should it be weak. It definitely needs to be strong.Mailer
It needs, when you don't use IB, that's obviuos, the clue of my question was "what keeps the strong pointer when you use IB?", because it isn't a controller, right? ;)Drover
@H2CO3 see my quote from the docs in my answer, specifically, "Outlets that you create should therefore typically be weak"Nari
@Nari Thanks for the explanation. (Yep, this is another reason why I don't use IB. I like to know what I am doing and I don't want some arbitrary subsystem to guess what I was intending to do.)Mailer
N
4

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

Nari answered 7/2, 2013 at 21:53 Comment(4)
thank you very much, this was the part of knowledge I was missing until now. Big thank you!Drover
The UINib does not own the objects it created after it's done instantiating them.Monophony
This isn't quite right. The UINib doesn't own the outlets, they are owned by the view - a view has strong references to its subviews. The weak reference was to free memory when the view was unloaded, which doesn't happen any more, so its sort of moot now.Subroutine
@Subroutine and Nikolai, fixed, apologies. Was on the wrong track at first.Nari
M
6

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

Monophony answered 7/2, 2013 at 22:10 Comment(1)
should be the accepted answer: it is much more clear than a copy past of Apple doc...Jolly
N
4

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

Nari answered 7/2, 2013 at 21:53 Comment(4)
thank you very much, this was the part of knowledge I was missing until now. Big thank you!Drover
The UINib does not own the objects it created after it's done instantiating them.Monophony
This isn't quite right. The UINib doesn't own the outlets, they are owned by the view - a view has strong references to its subviews. The weak reference was to free memory when the view was unloaded, which doesn't happen any more, so its sort of moot now.Subroutine
@Subroutine and Nikolai, fixed, apologies. Was on the wrong track at first.Nari
S
1

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.

Spasm answered 7/2, 2013 at 22:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.