要定义一个类,只要在 class 后面加上类名即可。在类中定义属性的写法与定义常量和变量一样,只不过它是在类的范围里。同样,方法的定义和函数定义是一样的写法。
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
试一试
用 let 增加一个常量属性,再加一个有一个参数的方法。
要创建类的实例,只需在类名后加上括号就可以了。用句点来访问类实例的属性和方法。
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 来创建一个析构函数。
要定义子类只需在类名后加分号,再写上父类的类名即可。Swift里并不要求类必须继承任何标准的父类,所以如果需要的话可以省略掉父类。
子类要重写父类的方法需要用 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()
试一试
加一个NamedShape的子类Circle,有radius属性,并且在初始化器中接收该参数。在Circle类里实现一个area() 和 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")
println(triangle.perimeter)
triangle.perimeter = 9.9
println(triangle.sideLength)
在周长的setter里,新的值有个被隐式的称为newValue的名字。你可以在set后面加个括号,显式地定义一个名字。
注意 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")
println(triangleAndSquare.square.sideLength)
println(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
println(triangleAndSquare.triangle.sideLength)
类里的方法与函数有一个很重要的不同。函数里的参数名只能用于函数内,但方法里的参数名还可以用在你调用该方法的时候(除了第一个参数)。默认情况下,方法调用时与方法自己内部,参数名是一样的。你可以再指定另一个名字,用于方法内。
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)
遇到可选值的时候,你可以在方法、属性和下标等操作前写个 ?。如果 ?前的值是 nil ,那么 ? 后的所有东西都会被忽略,而且整个表达式的值是nil。否则,可选值被开启,?后的所有东西按照开启值来继续。不管哪种情况,整个表达式的值都是可选值。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength