【问题标题】:Why does assigning with a strong property work, but not with a weak one?为什么分配强属性有效,而弱属性无效?
【发布时间】:2012-03-10 18:51:05
【问题描述】:

我的 .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。 IE。 self.levelPicker = blah 分配不起作用。

但是,如果我将属性声明更改为:

@property (strong, nonatomic) UIPickerView *levelPicker;

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

谁能告诉我为什么会这样?我以为我开始理解参考是如何工作的,但我想我还有更多的东西要学。我阅读了一些其他相关的 SO 帖子,但我仍然不完全清楚。

【问题讨论】:

    标签: objective-c ios automatic-ref-counting weak-references


    【解决方案1】:

    正如@Inazfiger 所说,您的对象至少需要一个强(保留)引用,否则它们将不会被保留。

    在这种情况下,您将选择器视图分配给UITextFieldinputView 属性。文本字段将保留选择器视图(我知道这是因为 UITextField 上的 inputView 属性是 declared with the modifiers "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 吗?
    • 您可以编写 textField.inputView = [[UIPickerView alloc] initWithFrame:frame] 然后直接配置 textField.inputView,但我会尽量避免这种情况,以防我分配给的属性(在本例中为 inputView)有一个带有逻辑的自定义设置器依赖于被分配对象的状态。
    • 这正是我正在寻找的答案。谢谢,也感谢@Inafziger。我想还有一个问题:在这里使用弱引用有什么好处,还是应该只使用强引用?
    • 嗯,这取决于你想从这段代码中得到什么。如果您希望(我怀疑)levelPicker 始终保持对对象的引用,即使它目前没有在其他任何地方使用,那么您应该使用强引用。确保在不再需要它时将其设置为 nil(通常在 viewDidUnload 中)!
    【解决方案2】:

    嗯,简短的回答是任务确实有效。

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

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

    有关详细信息,请参阅 Apple 的“过渡到 ARC 发行说明”中的“ARC Introduces New Lifetime Qualifiers”。

    Ray Wenderlich 在此 here 上创建了一个很棒的教程。

    【讨论】:

      【解决方案3】:

      “强”限定符创建了一个所有者关系,阻止对象被释放,这相当于您之前在非 ARC 世界中所做的:

      @property(retain) NSObject *obj;
      

      虽然“弱”限定符不会创建所有者关系,但对象将像以前一样被释放:

      @property(assign) NSObject *obj;
      

      在您的情况下,您需要第一个关系,因为您需要实例变量 (_levelPicker) 来保持新创建的 UIPickerView 实例。你所做的弱分配确实有效,但不久之后就被释放了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-11
        • 1970-01-01
        相关资源
        最近更新 更多