Objective-C中属性覆盖的危害是什么?

18

有几种情况下,您可能需要覆盖父类的属性。

  1. 您使用与其超类相同名称和相同属性的方式声明属性。(因为如果更改属性,则可能会出现编译器警告)。并且你可以用你创建的ivar进行综合。这有什么作用呢?或者它可能会带来什么危害吗?

  2. 如果超类在类扩展(没有名称的类别)中声明了一个属性,则该属性可能不在头文件中。如果您不从头文件中了解该属性,那么可以使用任何属性或类别声明相同名称的属性。但是setter/getter方法将覆盖该“秘密属性”的方法。我认为这只会带来危害。但由于您不从头文件中了解该属性,因此如何避免这种情况呢?

  3. 您可以在头文件中将属性声明为“只读”,然后在类扩展中重新声明为“可读写”。我认为这是它有益的情况。

我的理解对于这些情况是否正确?我不知道第一种和第二种情况有什么好处。但是,如果我想避免第一种情况,在声明它之前,我可以检查子类是否已经拥有该属性。但是,如果该属性不在公共头文件中,如第二种情况,则我就不知道该怎么办了。

2个回答

5
你所提到的每种情况都有适当的应用场景,在实际使用中使用时需要小心,以免出错。我将举个人经历的例子来说明。 子类化以有意覆盖属性
在这种情况下,就像Joe所提到的那样,你最好在覆盖属性之前确切地知道自己在做什么,并且没有其他选择。我个人发现,通常只需覆盖已有属性的一个setter或getter方法即可实现定制,而不是重新声明和合成属性。例如,考虑一个专门的UIView子类,只有具有UIClearColor背景才有意义。为了强制执行此操作,您可以覆盖-setBackgroundColor:,只需打印警告消息,然后不调用super的实现即可。我会说我从未有过完全覆盖属性的理由,但我不会说它在某些需要完全劫持现有属性的情况下可能是有用的工具。 私有属性
这比你想象的更有用。私有属性的替代方案是普通的ivar,我们都熟悉。如果这是一个频繁更改的ivar,您最终将得到看起来像这样的代码块:
[_myIvar release], _myIvar = nil;

或者:

[_myIvar release];
_myIvar = [someValue retain];

虽然看起来不错,但是像这样的内存管理样板代码很快就会变得非常老套。或者,我们可以将上面的示例实现为一个私有属性,具有保留语义。这意味着,无论如何,我们只需要:

self.myIvar = someValue;

这样做可以让阅读和输入更加轻松,您说得没错,由于这个属性对于其他人来说是不可见的,所以它可能会被子类意外覆盖。在Objective-C开发中,这是一种固有的风险,但您可以采取措施使该风险变得微乎其微。这些措施是通过以可预测的方式修改私有属性名称的变化来实现的。在这里,您可以选择无限的方法:例如,您可以制定一个个人策略,以自己的缩写和下划线作为私有属性名称的前缀。对于我来说,我会得到类似于mw_ivar,以及相应的-setMW_ivar:-mw_ivar访问器。是的,有统计学上的可能性,某人会意外地覆盖该名称,但事实上他们不会这么做。特别是如果您有一种向那些可能使用您的代码的人发布您的实践的方法。而且,我可以肯定地说,苹果公司并没有去制造那些被混淆的私有属性,因此在这方面您也是安全的。

公共只读,私有可读写
这只是标准做法。您说得对,这很有用,而且也不危险,因为属性在头文件中。任何意外覆盖它的人只能怪自己。


这个否则很好的答案中你错过的另一个用例是,用于在子类中指定更具体类型的属性。也就是说,在父类上有一个类型为id的属性。在子类上,您可以通过重新声明属性(例如NSString *)来使其更具体,并在子类中使用@dynamic propertyName来告诉编译器使用父类中的存储。 - Sandy Chapman

0

好问题

  1. 使用它的目的是,作为开发人员,您应该知道在这一点上您正在做什么,并且需要向基类属性添加自定义。由于您知道自己在做什么,除非您有充分的理由不这样做,否则您将正确地调用super的实现。决定不调用super可能会有害,特别是在您不知道基类如何实现的情况下。

  2. 是的,这是有害的,但可以通过不过度使用类别并仔细选择属性或方法名称并考虑前缀来避免。

  3. 是的,您是正确的,这对于限制访问您的属性很有好处。

#2的示例

@interface UIView(PFXextended)
-(NSArray*)PFXGetSubviewsOfType:(Class)class;
@end

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