web-dev-qa-db-fra.com

Swift: erreur "Doit appeler un initialiseur désigné de la super-classe" même si le code le fait

Le but est de sous-classer SCNNode. Selon le class docs , init(geometry geometry: SCNGeometry?) est un initialiseur désigné (aucun mot clé convenience n'est répertorié). Ce code n'invoque-t-il donc pas un initialiseur désigné de sa super-classe?

Pourquoi Xcode affiche-t-il l'erreur suivante?

Doit appeler un initialiseur désigné de la superclasse 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)
    }
}
8
Crashalot

Le problème est que vous essayez également d'accéder à vos propriétés PreviewNode avant d'appeler self.init ().

Essayez comme ça:

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
    }
}
7
Leo Dabus

Utilisé cette réponse, mais Leo Dabus mérite un crédit. Veuillez commenter si vous pouvez expliquer s’il est tout aussi valable de définir un nouvel initialiseur pratique que Leo l’a fait ou de remplacer l’initialiseur par défaut comme le fait cette réponse, ou si l’un est préférable l’autre.

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
    }
}
2
Crashalot

D'après ce que je comprends du Guide de Swift 4.2, les initialiseurs désignés doivent initialiser toutes les propriétés stockées. Les initiateurs de commodité peuvent initialiser un sous-ensemble de propriétés (ce qui peut être utile pour créer des instances dans des circonstances différentes). Ils doivent toutefois appeler un initialiseur désigné de la sous-classe qui à son tour appelle l'initialiseur désigné de la ou des superclasses pour initialiser toutes les propriétés stockées avant la personnalisation commence. Ce diagramme du guide rapide peut aider:

 enter image description here

En utilisant le mot clé de commodité, Leo peut alors appeler self.init (), qui est l'initialiseur désigné de PreviewNode, qui à son tour appelle l'initialiseur désigné de SCNNode. Cela résout l’erreur que nous avons tous les deux: l’initialisation 'obligatoire' initializer 'init (coder :)' doit être fournie par la sous-classe de 'SCNNode'. En effet, UIView adopte le protocole NSCoding.

Vous trouverez ci-dessous une version commentée du code de Leo indiquant les trois options permettant de gérer le problème. Je pense qu'ils sont tous également corrects, mais on peut résoudre un problème particulier mieux que d'autres.

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")
    }
    */
}

Désolé de remplacer un ancien message, mais le problème est le même et la recherche était amusante :-)

0
Tim