I have a property declared in my .h file as
@property (weak, nonatomic) UIPickerView *levelPicker;
which is synthezised in my implementation file as:
@synthesize levelPicker = _levelPicker;
I then have a code block in the same implementation file which 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. I.e. the self.levelPicker = blah assignment doesn't 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 the case? I thought I was coming to an understanding of how references work, but I guess I still have more to learn. I read some of the other related SO posts, but it's still not entirely clear to me.
As @Inazfiger says, your objects need at least one strong (retaining) reference, otherwise they won't be retained.
In this case, you're assigning the picker view to a UITextField's inputView property. The text field will retain the picker view (I know this because the inputView property on UITextField is declared with the modifiers "readwrite, retain"), but only once you've made the assignment. So if you want to stick with a weak reference, you need to rearrange your code slightly - 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's inputView property. This
// will increase the picker's 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 the assignment actually does work.
However, since it is a weak reference, it isn't retained since there is no (other) strong reference to your picker and it is automatically set to nil.
There has to be at least one strong reference to any object otherwise it isn't retained, which in this case there isn't.
For more information, see "ARC Introduces New Lifetime Qualifiers" in Apple's "Transitioning to ARC Release Notes".
Ray Wenderlich created a great tutorial on this here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With