سؤال

I am getting used to using weak and strong references and when to use them and when not and I got to a case like described below (check the comment about the warning)

@interface MPIViewController ()
@property (weak, nonatomic) UIView *subview;
@property (weak, nonatomic) UILabel *label;
@end

@implementation MPIViewController
// ...
// some code here
// ...  

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.subview = [[UIView alloc] init];   // warning here: assigning retained object to weak property 
    self.label = [[UILabel alloc] init];    // no warnings

    [self.view addSubView: self.subview];
    [self.view addSubView: self.label]; 
}

// ...
// some code here
// ...  
@end

From description of - (void)addSubview:(UIView *)view:

This method establishes a strong reference to view and sets its next responder to the receiver, which is its new superview.

This means that this object won't be deallocated after method finishes as it's superview will retain it and hold a strong reference to it and therefore this view will be kept in memory for as long as its superview is there. Am I right here?

I am not sure also if I understand assigning here correctly. Warning says that it will be deallocated straight after the assignment but this sounds wrong as then it wouldn't be possible to assign any variable to a weak pointer as it would get deallocated in the next line of code?

For UILabel same assign works fine, however for UIView it doesn't? Does the compiler treat UIView somehow differently? This really puzzles me how that is even possible.

This code can be fixed easily just by assigning the UIView to a local method variable and then passing it to the setter like this:

UIView *tmpView = [[UIView alloc] init];
self.subview = tmpView;

Variables declared in the method are by default strong so having such a construction removes the warning as the compiler thinks that this variable has a strong reference so weak reference that is then assigned to will be kept as long as the method variable will point to it. BUT! how does that make sense as the tmpView is only a local method variable and will be dumped after method will finish?

هل كانت مفيدة؟

المحلول

To the first question:

Let's have a closer look to it:

self.subview = [[UIView alloc] init];

[UIView alloc] returns an instance with ownership +1. This is assigned to a (non-visible) strong reference, which build the self of -init. -init passes the ownership through. (This is not correct, if -init returns an instance which is not the original receiver, but for your case it is enough details.) So we can think of the return value of -init as an ownership transfer, too.

You assign this instance to a weak variable. In this moment it can be released. (Read: ARC does not promise to do it immediately, IIRC.) the instance variable can be nil before the object is hold by its superview. So this code is dangerous:

self.subview = [[UIView alloc] init];
// _subview can be nil'ed
[self.view addSubView: self.subview]; // add nil

I do not believe that this is your problem, but it can be a problem. – Thinking again about it, it is your problem. Read the edit at the end. –To get rid of it, simply use a strong local variable:

UIView *subview = [[UIView alloc] init]; // defaults to __strong
[self.view addSubView: subview]; // adds an ownership
self.subview = subview;

The second question:

I do not know, why the compiler gives you no warning in the second case. What does happen, if you repair the first case?

At runtime a different handling of both cases is possible, because it is undefined, when the first instance is released. Maybe as a part of optimization a pointer is reused. More detailed:

__strong id completlyHiddenCompilerGeneratedVar;
… = [(completlyHiddenCompilerGeneratedVar=[UIView alloc]) init];
… = [(completlyHiddenCompilerGeneratedVar=[UILabel alloc]) init];

The first instance would be dealloc'ed, when the second instance is created, because it overwrites the internal strong reference.

Again: Repair the first case and tell us, what happens with the second one.

نصائح أخرى

An object need at least one strong pointer to it in order to be kept in memory.

So when you alloc it to a weak pointer that condition is not being met. Make your properties strong if you really need to access these views.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top