一尘不染

在Swift子类中添加便捷初始化器

swift

作为学习练习,我尝试实现一个子类,SKShapeNode该子类提供一个新的便捷初始化器,该初始化器采用一个数字并构造一个ShapeNode,该ShapeNode是一个数字宽度和高度的平方。

根据《雨燕书》

规则1

如果您的子类没有定义任何指定的初始化器,它将自动继承其所有超类的指定初始化器。

规则二

如果您的子类提供了其所有超类指定初始化器的实现(通过按照规则1继承它们,或通过提供自定义实现作为其定义的一部分),那么它将自动继承所有超类便利性初始化器。”

但是,以下类不起作用:

class MyShapeNode : SKShapeNode {
    convenience init(squareOfSize value: CGFloat) {
        self.init(rectOfSize: CGSizeMake(value, value))
    }
}

相反,我得到:

Playground execution failed: error: <REPL>:34:9: error: use of 'self' in delegating initializer before self.init is called
        self.init(rectOfSize: CGSizeMake(value, value))
    ^
<REPL>:34:14: error: use of 'self' in delegating initializer before self.init is called
    self.init(rectOfSize: CGSizeMake(value, value))
         ^
<REPL>:35:5: error: self.init isn't called on all paths in delegating initializer
}

我的理解是,MyShapeNode应该继承所有SKShapeNode的便捷初始化器,因为我没有实现自己指定的任何初始化器,并且由于便捷初始化器正在调用init(rectOfSize),另一个便捷初始化器应该可以工作。我究竟做错了什么?


阅读 443

收藏
2020-07-07

共1个答案

一尘不染

我对Initializer
Inheritance的理解与您的理解相同,并且我认为我们都与本书所陈述的保持一致。我认为这不是解释性问题,也不是对规定规则的误解。也就是说,我认为您没有做错任何事情。

我在Playground中测试了以下内容,它可以按预期工作:

class RectShape: NSObject {
    var size = CGSize(width: 0, height: 0)
    convenience init(rectOfSize size: CGSize) {
        self.init()
        self.size = size
    }
}

class SquareShape: RectShape {
    convenience init(squareOfSize size: CGFloat) {
        self.init(rectOfSize: CGSize(width: size, height: size))
    }
}

RectShape继承自NSObject且未定义任何指定的初始值设定项。因此,根据规则1,它继承了所有NSObject指定的初始化程序。在为实例进行设置之前,我在实现中提供的便捷初始化程序正确地委派给了指定的初始化程序。

SquareShape从继承RectShape,不提供指定的初始值设定项,按照规则1的规定,继承所有SquareShape的指定的初始值设定项。根据规则2,它还继承了中定义的便捷初始化程序RectShape。最后,定义的便捷初始化程序SquareShape正确地委派给继承的便捷初始化程序,后者又委托给继承的指定初始化程序。

因此,鉴于您没有做错任何事且我的示例按预期运行,我在推断以下假设:

因为SKShapeNode是用Objective-
C编写的,所以该语言没有强制执行“每个便利初始化程序必须从同一类调用另一个初始化程序”的规则。因此,也许便利初始化SKShapeNode器实际上并未调用指定的初始化器。因此,即使子类MyShapeNode按预期继承了便利初始化程序,它们也无法正确地委派给继承的指定初始化程序。

但是,这只是一个假设。我可以确认的是,在我自己创建的两个类上,该机制都按预期工作。

2020-07-07