用class加上类名就创建一个类了。属性的声明方法和普通的常量变量的声明方法相同,唯一的区别就是属性是在类的上下文中。同样地,方法和函数的声明也一样。
class Shape {
var numberOfSides = 0
func simpleDescription() ->String {
return "A shape with \(numberOfSides) sides."
}
}
创建一个类的实例是直接在类名后面加括号()。用点语法访问实例的属性和方法。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
但是这个Shape类没有在创建实例的时候初始化属性。添加一个init初始化类。
class NamedShape {
var numberOfSides:Int = 0
var name:String
init(name:String ){
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
注意在初始化时self是如何区别参数name和属性name的。当你创建一个实例时像函数的调用的方法一样传入构造器参数。每一个属性都需要赋值=要么在声明(numberOfSides)的时候,要么在初始化时(name)。
在这个对象销毁前用deinit(看这个名字就知道是init的反义词)折构函数做一些清理操作。
子类要继承父类,在子类名称后面加上分号:。 没有要求类必须继承一个标准根类,所以你可以忽略根类。
子类可以重写父类声明的方法,即在方法前加上 override,如果没有加override就重写的话会报错。编译器也会检查有override的方法在父类中存不存在。
class Square:NamedShape {
var sideLength: Double
init(sideLength:Double,name:String) {
self.sideLength = sideLength
super.init(name:name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength:5.2,name:"my test square")
test.area()
test.simpleDescription()
除了存储一些简单的属性,类还可以定义一些计算属性,计算属性不直接存储值,而是通过getter和setter,间接提取和设定值。
class EquilateralTriangle:NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name:name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() ->String{
return "An equilateral triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength:3.1,name:"a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
在perimeter的setter中,参数被隐含地命名为newValue。你也可以将参数名字在set后面用括号括起来。
var perimeter: Double {
get {
return 3.0 * sideLength
}
set { (newValue)
sideLength = newValue / 3.0
}
}
注意EquilateralTriangle的构造器有三个步骤
- 给当前类声明的属性赋值
- 调用父类的构造器
- 改变父类定义的属性。其他工作比如调用方法,getter,setter也可以在这里完成。
如果你不需要一个计算属性但是仍然想在代码运行前后设定新值的话,可以使用willSet和DidSet。
比如,下面的这个类确保了三角形的边长和正方形的边长始终想等。
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name:String) {
square = Square(sideLength:size, name:name)
triangle = EquilateralTriangle(sideLength:size, name:name)
}
}
var triangleAndSquare = TriangleAndSquare(size:10, name:"another test shape")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength:50, name:"larger square")
print(triangleAndSquare.triangle.sideLength)
当处理可选类型,你可以在方法属性和subscripting 前面加上问号?。如果?号前面的值是nil,那么问号后面的所有值都是nil.否则,?之后的所有代码都会运行。在这两种情况下,整个表达式的值是可选类型的。
let optionalSquare :Square? = Square(sideLength:2.5, name:"optional square")
let sideLength = optionalSquare?.sideLength