目标是子类化SCNNode。根据class docs,init(geometry geometry: SCNGeometry?)
是一个指定的初始化器(没有列出convenience
关键字),所以这个代码不是调用其超类的指定初始化器吗?
为什么Xcode显示以下错误?
必须调用超类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'initulator'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")
}
*/
}
很抱歉碰到一个旧帖子,但我遇到了同样的问题,研究很有趣:-)