被属性设置者的行为弄糊涂了



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

我有一个属性为的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:等方法返回有用的信息,这与最初产生Objective-C的Smalltalk的影响不同。在Smalltalk中,addSubview:方法返回添加的对象是预期的/常见的。如果是这种情况,可以将这些表达式写成:

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

这将允许强/弱语义是令人满意的。addSubview:在到达弱label设置器之前会进行强保留。

我用subviewsrecognizers来解决这个问题,所以我觉得我会很聪明,写一个category来做类似的事情(我反转了receiver/argument,这样它就可以很容易地与另一个addSubview:signature区分开来)。

@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"。我不知道Objective-C伪类型,这意味着是这个已知超类型的正确的该死的子类型,以使属性类型满意

最终更新

我发现了instancetype类型。通过更改我的类别方法签名以返回这些类型,一切都正常工作。我是instancetype的新手,不知道我是否在这里滥用了什么,但我很高兴它奏效了。

警告来自:

self.label = [UILabel new]

因为您的CCD_ 23属性是CCD_。

您是正确的,它最终会工作,因为对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];

相关内容

  • 没有找到相关文章

最新更新