对属性设置器的行为感到困惑

时间:2014-11-11 17:50:23

标签: ios objective-c properties weak-references

(这个问题可能需要一个更具描述性的标题,随时改进它)

我有一个带有属性的UIView子类:

@property (weak, nonatomic) UILabel *label;

我用initialize方法:

[self addSubview: (self.label = [UILabel new])];

我喜欢这个的简洁,但我对它是如何工作有疑问。

首先,我收到警告:

Assigning retained object to weak property; object will be released after assignment

警告一边,它实际上似乎有效。那是因为在发布机制运行之前,addSubview:重新保留它吗?

如果我理解正确,self.label = ...代码只是[self setLabel: ...]的糖。但是如果我用我自己的setLabel:实现覆盖属性访问,它的签名将是

- (void) setLabel: (UILabel*) label;

因此返回值为 void 。但它被送入addSubview:发送和工作?那怎么办呢?

更新

令人沮丧的是,在这里做一个班轮的事情之一就是Objective-C倾向于避免从addSubview:这样的方法中返回有用的信息,这些信息与产生的Smalltalk影响不同-C首先。在Smalltalk中,addSubview:方法返回添加的对象是预期/常见的。如果是这种情况,可以将这些表达式写为:

self.label = [self addSubview: [UILabel new]];

这将允许强/弱语义快乐。 addSubview:会在到达弱label二传手之前进行强保留。

我用subviewsrecognizers来解决这个问题,所以我觉得我很聪明,写一个category来做那样的事情(我倒了接收器/ argument因此很容易与备用addSubview区分开来:签名)。

@interface UIView (UIView_Adding)
    - (UIView*) addedToView: (UIView*) superview;
@end

@interface UIGestureRecognizer (UIView_Adding)
    - (UIGestureRecognizer*) addedToView: (UIView*) view;
@end

@implementation UIView (UIView_Adding)
- (UIView*) addedToView: (UIView*) superview {
    [superview addSubview: self];
    return self;
}
@end

@implementation UIGestureRecognizer (UIView_Adding) 
- (UIGestureRecognizer*) addedToView: (UIView*) view {
    [view addGestureRecognizer: self];
    return self;
}
@end

不幸的是,这只是引用了丑陋的守恒定律。我摆脱了一种警告并获得另一种警告。有了这个类别,我现在可以写:

self.label = [[UILabel new] addedToView: self];

但是这会产生一个警告,self.label意味着保留UIView的特定子类,即UILabel,返回类型addedToView:是`UIView&#39 ;。我不知道Objective-C伪类型,这意味着是这个已知超类型的正确darn子类型,以使属性类型更快乐。 :(

最终更新

我发现了instancetype类型。通过更改我的类别方法签名以返回这些类型,一切正常。我已经足够新instancetype不知道我是否在这里滥用了一些东西,但我很激动它有效。

1 个答案:

答案 0 :(得分:2)

警告来自:

self.label = [UILabel new]

因为您的label属性为weak

你说它是正确的,因为调用addSubview:会保留标签。

但是,如果标签已从其超级视图中删除,则label属性将变为nil,标签将丢失。因此,如果有可能删除标签但您想保留对标签的引用(可能稍后再添加),则将您的属性更改为strong

self.label =实际上只是[self setLabel:],这也是正确的。这可以传递给addSubview:的原因是因为x = y之类的表达式的值等于赋值。

所以:

[self addSubview: (self.label = [UILabel new])];

如果相当于:

UIView *view = (self.label = [UILabel new]);
[self addSubview:view];