Swift: "Must call a designated initializer of the superclass" 错误,即使代码正在这样做

Swift: "Must call a designated initializer of the superclass" error even though code is doing so

目标是子类化 SCNNode。根据 class docsinit(geometry geometry: SCNGeometry?) 是一个指定的初始化器(没有列出 convenience 关键字),所以这段代码不是调用其超类的指定初始化器吗?

为什么 Xcode 显示以下错误?

Must call a designated initializer of the superclass SCNNode

class PreviewNode: SCNNode {
    // Constants
    let PreviewNodeColor = gRedColor
    let Size = CGFloat(1.0)
    let ChamferRadius = CGFloat(0.0)

    override init() {
        let previewBox = SCNBox(width: Size, height: Size, length: Size, chamferRadius: ChamferRadius)
        previewBox.firstMaterial!.diffuse.contents = PreviewNodeColor
        previewBox.firstMaterial!.transparency = 0.2
        previewBox.firstMaterial!.specular.contents = UIColor.whiteColor()
        super.init(geometry: previewBox)
    }
}

问题是您在调用 self.init()

之前还试图访问您的 PreviewNode 属性

这样试试:

Xcode 8 GM • Swift 3

class PreviewNode: SCNNode {
    let previewNodeColor: UIColor = .red
    let size: CGFloat = 1
    let chamferRadius: CGFloat = 0
    convenience override init() {
        self.init()
        let previewBox = SCNBox(width: size, height: size, length: size, chamferRadius: chamferRadius)
        previewBox.firstMaterial?.diffuse.contents = previewNodeColor
        previewBox.firstMaterial?.transparency = 0.2
        previewBox.firstMaterial?.specular.contents = UIColor.white
        self.geometry = previewBox
    }
}

使用了这个答案,但 Leo Dabus 值得赞扬。如果您可以解释是否像 Leo 那样定义一个新的便利初始值设定项或像这个答案那样覆盖默认初始值设定项是否同样有效,或者是否一个比另一个更可取,请发表评论。

class PreviewNode: SCNNode {
    // Constants
    let MainColor = gRedColor
    let MainSize = CGFloat(1.0)
    let MainRadius = CGFloat(0.0)
    let MainTransparency = CGFloat(0.2)


    override init() {
        super.init()
        doInit()
    }


    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    private func doInit() {
        let previewBox = SCNBox(width: MainSize, height: MainSize, length: MainSize, chamferRadius: MainRadius)
        previewBox.firstMaterial!.diffuse.contents = MainColor
        previewBox.firstMaterial!.transparency = MainTransparency
        previewBox.firstMaterial!.specular.contents = UIColor.whiteColor()
        self.geometry = previewBox
    }
}

我对 Swift 4.2 指南的理解是指定的初始化程序必须初始化所有存储的属性。便利初始化器可以初始化属性的一个子集(这可能对在不同情况下创建实例很有用)但是,它们必须首先调用子类的指定初始化器,然后调用超类的指定初始化器来初始化所有存储的属性在定制开始之前。 Swift 指南中的这张图可能会有所帮助:

通过使用方便的关键字 Leo 可以调用 self.init() 这是 PreviewNode 的指定初始化程序,后者又调用 SCNNode 的指定初始化程序。这就解决了我们都得到的错误:'required' 初始化程序 'init(coder:)' 必须由 'SCNNode' 的子类提供。那是因为UIView采用了NSCoding协议。

下面是 Leo 代码的注释版本,其中显示了处理该问题的三个选项。我认为它们都同样正确,但一个可能比其他更适合特定问题。

import SceneKit
class PreviewNode: SCNNode {
    let previewNodeColor: UIColor = .red
    let size: CGFloat = 1
    let chamferRadius: CGFloat = 0
    //convenience override init() {   //Option 1 - use with self.init() to use the default designated initialisers up the inheritance ladder
    //override init() {               //Option 2 - use with super.init() and the additional required initialiser below
    required init(coder aDecoder: NSCoder) {  //Option 3 - Use with super.init() to initialise the geometry property of SCNNode and the required intialiser
        //self.init()
        super.init()
        let previewBox = SCNBox(width: size, height: size, length: size, chamferRadius: chamferRadius)
        previewBox.firstMaterial?.diffuse.contents = previewNodeColor
        previewBox.firstMaterial?.transparency = 0.2
        previewBox.firstMaterial?.specular.contents = UIColor.white
        self.geometry = previewBox
    }
    //Use with Option 2 to provide the additional required initialiser for NSCoder
    /*
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    */
}

抱歉撞到一个旧的 post 但我遇到了同样的问题而且研究很有趣 :-)