为什么使用强引用属性可以工作,但是使用弱引用属性却无法工作?

3

我在我的.h文件中声明了一个属性

@property (weak, nonatomic) UIPickerView *levelPicker;

这在我的实现文件中被合成为:

@synthesize levelPicker = _levelPicker;

我随后在同一个实现文件中有一个代码块,执行以下操作:
if (self.levelPicker == nil) {
    self.levelPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
    self.levelPicker.delegate = self;
    self.levelPicker.dataSource = self;
}
textField.inputView = self.levelPicker;

在这种情况下,self._levelPicker没有设置为新的UIPickerView。即,self.levelPicker = blah赋值不起作用。
然而,如果我将属性声明更改为:
@property (strong, nonatomic) UIPickerView *levelPicker;

然后一切都按照预期工作,_levelPicker被设置为新分配的UIPickerView。

有人能告诉我为什么会这样吗?我以为我已经理解了引用的工作原理,但我想我还有更多要学习的。我阅读了一些其他相关的SO帖子,但对我来说仍然不是完全清楚的。

3个回答

7
正如@Inazfiger所说,您的对象需要至少一个强引用(保留引用),否则它们将不会被保留。
在这种情况下,您将选择器视图分配给UITextFieldinputView属性。文本字段将保留选择器视图(我知道这是因为UITextField上的inputView属性是使用修饰符“readwrite,retain”声明的),但是只有在进行分配之后。因此,如果您想坚持使用弱引用,您需要稍微重新安排一下代码-类似于这样:
// 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;

你能不能直接跳过临时变量,在它超出作用域之前将其直接分配给inputview? - lnafziger
你可以编写 textField.inputView = [[UIPickerView alloc] initWithFrame:frame],然后直接配置 textField.inputView,但我尽量避免这样做,以防所分配的属性(在此情况下为 inputView)具有依赖于被分配对象状态的自定义 setter 逻辑。 - Simon Whitaker
这正是我在寻找的答案。谢谢,也感谢@Inafziger。我想进一步提问:在这里使用弱引用是否有任何优势,或者我应该只使用强引用? - BennyFlint
这取决于您从此代码中想要什么。如果您想(正如我所怀疑的那样)让levelPicker始终保持对对象的引用,即使它目前在其他任何地方都没有使用,那么您应该使用强引用。但是请确保在不再需要它时将其设置为nil(通常在viewDidUnload中)! - lnafziger

4

简单来说,这个赋值确实起作用。

但是,由于它是一个弱引用,因此在没有(其他)强引用到您的选择器时,它不会被保留并自动设置为nil。

任何对象都必须至少有一个强引用,否则它就不会被保留,而在这种情况下就没有强引用。

有关更多信息,请参见苹果公司的“ARC引入新的生命周期限定符”。

Ray Wenderlich在这里创建了一个很好的教程。


1

"strong"限定符创建了一个所有者关系,防止对象被释放,这相当于在非ARC世界中以前所做的操作:

@property(retain) NSObject *obj;

尽管“弱”限定词不会创建所有者关系,因此您可以像以前一样对对象进行解除分配:

@property(assign) NSObject *obj;

在您的情况下,您需要第一个关系,因为您需要实例变量(_levelPicker)保存新创建的UIPickerView实例。您执行的弱引用确实起作用,但很快就被释放了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接