【问题标题】:Setting property on superclass from subclass?从子类设置超类的属性?
【发布时间】:2014-03-19 13:12:18
【问题描述】:

我正在研究SKNode 的一个子类,称为UtilityNode

@implementation UtilityNode

- (id)initWithName:(NSString *)rootName {
    self = [super init];
    if(self) {
        [self setName:rootName]; // ?
    }
    return self;
}

@end

我正在为新节点initWithName: 设置一个指定的初始化程序,我在创建新子类时尝试初始化超类的名称SKNode。我的印象是我可以写 _name = rootName; 但 _name 被标记为未声明。我已经使用[self setName:rootName]; 让它工作了(如您在上面看到的)有人可以对此有所了解吗,我这样做是否正确?

【问题讨论】:

  • 可能是你可以向超类添加一些方法而不是在超类中添加相同的方法,例如initWithName 和 self = [super initWithName:rootName] ?只是一个想法不确定

标签: ios objective-c sprite-kit sknode


【解决方案1】:

这是正确的。 _name 实例变量可能被声明为 @private(自动合成属性的默认值),因此子类无法访问它。

在精心设计的类层次结构中,特别是没有可用源代码的框架类中,您会发现大多数(如果不是所有)实例变量都无法被子类访问,因为它隐藏了实现细节并使未来对基类的更改成为可能。想象一下,如果基类需要在 name 属性更改时验证它 - 如果子类可以直接分配给 ivar,它们将绕过添加到 ivar setter 方法的检查。

PS:我发现点符号对眼睛更友好:

 self.name = rootName;

更新关于“不要在 init/dealloc 中向self 发送消息”规则:

这可以通过重新设计类以在其 init 方法中不采用非必要参数来轻松避免。这个子类的更简洁的版本是:

UtilityNode* un = [UtilityNode node];
un.name = @"some name";

如果节点绝对需要设置参数,请在要求名称有效的方法中通过NSAssert 警告用户。

【讨论】:

  • 在任何init 方法中都不应该访问self 的“规则”怎么样?
  • Lance 说的很好,这就是为什么我开始尝试使用 _name 我想在这种情况下使用 self 是可以的。
  • 谢谢 Steffen,我就是这么想的,但我只是想得到一些确认,非常感谢。
  • “不要在 init 中向自己发送消息”具有非常特殊的情况,可能会产生不良副作用。例如,它要求您在 init 中访问 self 的类具有一个子类,并且该子类已覆盖您将其发送到的消息。只要您不覆盖 setName: 在 UtilityNode 或其子类中,您就不必担心这一点。 OTOH 框架设计者确实需要考虑它。 stackoverflow.com/questions/3150494/…
  • 感谢 Steffen 的更新,这是关于在 init 之外设置名称的一个好点,这就是我对其他 SKNode (如 SKSpriteNode)所做的事情,所以我会按照您在更新中建议的方式进行操作。再次感谢您的时间和精力。
猜你喜欢
  • 2019-01-30
  • 2021-03-13
  • 2017-08-03
  • 1970-01-01
  • 2013-03-24
  • 2017-04-18
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多