(这个问题可能需要一个更具描述性的标题,随时改进它)
我有一个带有属性的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
二传手之前进行强保留。
我用subviews
和recognizers
来解决这个问题,所以我觉得我很聪明,写一个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
不知道我是否在这里滥用了一些东西,但我很激动它有效。
答案 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];