Properties Swift类出错:在super.init调用时未初始化属性

Properties Swift类出错:在super.init调用时未初始化属性,properties,compiler-errors,swift,Properties,Compiler Errors,Swift,我有两个班,Shape和Square class Shape { var numberOfSides = 0 var name: String init(name:String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } } class Sq

我有两个班,
Shape
Square

class Shape {
    var numberOfSides = 0
    var name: String
    init(name:String) {
        self.name = name
    }
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

class Square: Shape {
    var sideLength: Double

    init(sideLength:Double, name:String) {
        super.init(name:name) // Error here
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}
通过上面的实现,我得到了错误:

property 'self.sideLength' not initialized at super.init call
    super.init(name:name)

为什么我必须在调用
super.init
之前设置
self.sideLength

swift强制您在使用/可能使用每个成员变量之前初始化它。由于它无法确定在超级转弯时会发生什么,因此会出错:安全总比抱歉好

引用Swift编程语言,它回答了您的问题:

“Swift的编译器执行四项有用的安全检查以确保 两阶段初始化已完成且无错误:

安全检查1“指定的初始值设定人必须确保 “由其类引入的属性在初始化之前初始化 委托给一个超类初始值设定项。“

摘自:苹果公司《Swift编程语言》。iBooks。

对不起,格式很难看。 只需在声明后添加一个问题字符,一切都会好起来的。 一个问题告诉编译器该值是可选的

class Square: Shape {
    var sideLength: Double?   // <=== like this ..

    init(sideLength:Double, name:String) {
        super.init(name:name) // Error here
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}
Edit2:

在得到这个答案的两个负数后,我找到了更好的方法。如果您希望在构造函数中初始化类成员,则必须在构造函数内部和super.init()调用之前为其指定初始值。如下所示:

class Square: Shape {
    var sideLength: Double  

    init(sideLength:Double, name:String) {
        self.sideLength = sideLength   // <= before super.init call..
        super.init(name:name)
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}
类方形:形状{
var边长:双
init(边长:Double,名称:String){
self.sideLength=sideLength//Double{
返回边长*边长
}
}

学习Swift祝你好运。

Swift有一个非常清晰、具体的操作序列,这些操作是在初始化程序中完成的。让我们从一些基本示例开始,逐步学习到一般情况

让我们以一个对象A为例,定义如下

class A {
    var x: Int
    init(x: Int) {
        self.x = x
    }
}
请注意,A没有超类,因此它无法调用super.init()函数,因为它不存在

好的,现在让我们用一个名为B的新类创建一个子类A

class B: A {
    var y: Int
    init(x: Int, y: Int) {
        self.y = y
        super.init(x: x)
    }
}
这与Objective-C不同,在Objective-C中,通常先调用
[super init]
。在Swift中不是这样。在执行任何其他操作之前,包括调用方法(包括超类的初始值设定项),您有责任确保实例变量处于一致状态。

“super.init()”应该在初始化所有实例变量后调用

在苹果的“Intermediate Swift”视频中(您可以在Apple Developer视频资源页面中找到),大约在28:40,明确地说,在初始化实例变量之后,必须调用super类中的所有初始值设定项

在Objective-C中,情况正好相反。在Swift中,由于所有属性在使用之前都需要初始化,因此我们需要首先初始化属性。这意味着防止在不初始化属性的情况下,从超类的“init()”方法调用重写的函数

因此,“广场”的实施应该是:

class Square: Shape {
    var sideLength: Double

    init(sideLength:Double, name:String) {
        self.sideLength = sideLength
        numberOfSides = 4
        super.init(name:name) // Correct position for "super.init()"
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}
爱德华

您可以修改示例中的代码,如下所示:

var playerShip:PlayerShip!
var deltaPoint = CGPointZero

init(size: CGSize)
{
    super.init(size: size)
    playerLayerNode.addChild(playerShip)        
}
这是使用隐式展开的可选项

class Square: Shape {
    var sideLength: Double?   // <=== like this ..

    init(sideLength:Double, name:String) {
        super.init(name:name) // Error here
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}
在文档中,我们可以阅读:

“与期权一样,如果您在购买时未提供初始值 声明隐式展开的可选变量或属性,它是 值自动默认为零。”


Swift将不允许您在不初始化属性的情况下初始化super类,与Obj C相反。因此,您必须在调用“super.init”之前初始化所有属性

请去。
它很好地解释了您的问题。

在声明末尾添加nil



这对我的案子有效,但从法律上看可能对你的案子无效

安全检查1

指定的初始值设定项必须确保所有属性 由其类引入的,在将其委托给 超类初始值设定项


为什么我们需要这样的安全检查?

为了回答这个问题,让我们用swift完成初始化过程

两阶段初始化

Swift中的类初始化是一个两阶段的过程 阶段,每个存储的属性由类指定一个初始值 这就引入了它。一旦每个存储属性的初始状态 已确定,第二阶段开始,并给出每个类 有机会在发布之前进一步自定义其存储属性 新实例被认为可以使用

使用两个阶段的初始化过程进行初始化 安全,同时仍然为类中的每个类提供完全的灵活性 层次结构。两阶段初始化可防止属性值 在初始化之前被访问,并阻止属性 值被另一个初始值设定项设置为不同的值 想不到

因此,为了确保按照上述定义完成两步初始化过程,有四个安全检查,其中一个是

安全检查1

指定的初始值设定项必须确保所有属性 由其类引入的,在将其委托给 超类初始值设定项

现在,两阶段初始化从未讨论顺序,但是这个安全检查在初始化所有属性之后引入了要排序的
super.init

安全检查1可能看起来不相关, 两阶段初始化可防止在属性值初始化之前对其进行访问,而无需进行此安全检查1

就像这个样本一样

class Shape {
    var name: String
    var sides : Int
    init(sides:Int, named: String) {
        self.sides = sides
        self.name = named
    }
}

class Triangle: Shape {
    var hypotenuse: Int
    init(hypotenuse:Int) {
        super.init(sides: 3, named: "Triangle") 
        self.hypotenuse = hypotenuse
    }
}
Triangle.init
已初始化,每个属性在使用前都已初始化。因此安全检查1似乎不相关

但可能还有另一种情况,有点复杂

class Shape {
    var name: String
    var sides : Int
    init(sides:Int, named: String) {
        self.sides = sides
        self.name = named
        printShapeDescription()
    }
    func printShapeDescription() {
        print("Shape Name :\(self.name)")
        print("Sides :\(self.sides)")
    }
}

class Triangle: Shape {
    var hypotenuse: Int
    init(hypotenuse:Int) {
        self.hypotenuse = hypotenuse
        super.init(sides: 3, named: "Triangle")
    }

    override func printShapeDescription() {
        super.printShapeDescription()
        print("Hypotenuse :\(self.hypotenuse)")
    }
}

let triangle = Triangle(hypotenuse: 12)
输出:

Shape Name :Triangle
Sides :3
Hypotenuse :12
如果我们调用了<代码
Shape Name :Triangle
Sides :3
Hypotenuse :12
     class Shape2 {
        var numberOfSides = 0
        var name: String
        init(name:String) {
            self.name = name
        }
        func simpleDescription() -> String {
            return "A shape with \(numberOfSides) sides."
        }
    }

    class Square2: Shape2 {
        var sideLength: Double

        init(sideLength:Double, name:String) {

            self.sideLength = sideLength
            super.init(name:name) // It should be behind "self.sideLength = sideLength"
            numberOfSides = 4
        }
        func area () -> Double {
            return sideLength * sideLength
        }
    }