Why assignment with strong property works but not weak property?

I have a property declared in my .h file as

@property (weak, nonatomic) UIPickerView *levelPicker;


which is synthesized in my implementation file as:

@synthesize levelPicker = _levelPicker;


Then I have a code block in the same implementation file that does the following:

if (self.levelPicker == nil) {
    self.levelPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
    self.levelPicker.delegate = self;
    self.levelPicker.dataSource = self;
textField.inputView = self.levelPicker;


In this case, self._levelPicker is not set to the new UIPickerView. That is, the assignment to self.levelPicker = blah does not work.

However, if I change the property declaration to:

@property (strong, nonatomic) UIPickerView *levelPicker;


then everything works as expected and _levelPicker is set to the newly allocated UIPickerView.

Can someone please tell me why this is so? I thought I was coming to understand how links work, but I think I have even more to learn. I've read some of the other related SO posts, but it's still not entirely clear to me.


source to share

3 answers

As @Inazfiger reports, your objects need at least one strong (persisting) reference, otherwise they won't be persisted.

In this case, you are assigning the selection view to the property UITextField


. The text box will keep the selection view (I know this because the property inputView

is not UITextField

declared with the "readwrite, save " modifiers ), but only after the job is done . So if you want to stick with a weak link, you need to modify your code a little - something like this:

// Declare a temporary UIPickerView reference. By default, this is
// a strong reference - so tempPicker will be retained until this
// variable goes out of scope.
UIPickerView *tempPicker = [[UIPickerView alloc] initWithFrame:frame];

// Configure the picker
tempPicker.delegate = self;
tempPicker.dataSource = self;

// Assign the picker view to the text field inputView property. This
// will increase the picker retain count. Now it'll no longer be
// released when tempPicker goes out of scope.
textField.inputView = tempPicker;

// Finally, assign the same object to self.levelPicker - it won't
// go out of scope as long as it remains assigned to textField's
// inputView property, and textField itself remains retained.
self.levelPicker = tempPicker;




Well, the short answer is that assignment actually works.

However, since this is a weak reference, it is not saved as there is no (other) strong reference to your collector, and it is automatically set to zero.

There must be at least one strong reference to any object, otherwise it will not be saved, which in this case will not be.

For more information, see "ARC Introduces New Lifetime Qualifiers" in Apple's Go to ARC Release Notes.

Ray Wenderlich has created a great tutorial on this here .



The "strong" qualifier creates an owner relationship that stops the object from being freed, which is equivalent to what you did earlier in a non-ARC world:

@property(retain) NSObject *obj;


Whereas the "weak" qualifier does not create an owner relationship, so the object will be deallocated as before:

@property(assign) NSObject *obj;


In your case, you need the first relationship because you need your instance variable (_levelPicker) to hold onto the newly created UIPickerView instance. A weak assignment that you actually did work, but it was released shortly after.



All Articles