Classes and Objects
github:Swift基础实例
github:SwiftBasicTableView
- 类的创建
使用关键字class
,后面跟上类名称,来创建一个类。
class Shape {
var numberOfSides = 0
let numberOfPoint = 3
func simpleDescription() ->String {
return "A shape with \(numberOfSides) sides"
}
func simplePoint(point:Int) ->Int {
return point
}
}
通过在类名后加圆括号()
来创建类的实例。用点语法(dot syntax),也就是对象加点调用
来访问实例中的属性和方法:
var shape = Shape()
shape.numberOfSides = 1
var shapeDes = shape.simpleDescription()
print(shapeDes)
- 构造器
上面的类Shape
少了一个重要的东西:当一个实例被创建的时候,用来构造这个类的初始化方法(可以称为构造器
)。用init
来生成一个这样的方法:
class NameShape {
var numberOfSides: Int = 0
var name :String
init(name:String) {
self.name = name
}
func simpleDescription() ->String {
return "A shape with a name \(name)"
}
}
var nameShape = NameShape(name: "ssss")
var initName = nameShape.simpleDescription()
- 在创建类的实例的时候,它的一个属性
name
在初始化方法中被初始化 - 每一个属性如果不是可选类型(加
?
进行声明),都 必须 赋值---无论是numberOfSides
还是初始化方法中的name
- 析构器
在对象释放时,可以在析构器中做些清理工作,用关键字deinit
来生成一个析构器:
class NameShapeTwo {
var numberOfSides: Int
init(number:Int) {
print("init called")
self.numberOfSides = number
}
deinit {
print("deinit called")
numberOfSides = 0
}
func addNumbers(number:Int) {
numberOfSides += 3
}
}
var shapeTwo :NameShapeTwo? = NameShapeTwo(number: 3)
print("numberOfSides : \(shapeTwo!.numberOfSides)")
shapeTwo = nil
- 输出顺序为:
init called numberOfSides : 3 deinit called
- 类的继承
子类包含父类的名字,用冒号:
将子类名和父类名隔开。如果子类要重写/使用 父类已经定义过的方法,子类 必须 在该方法前加override
关键字,如果不写override
编译器会报错。而且编译器还会检测那些带有override
的方法,判断这些方法是否是真的重写父类中的方法:
class Square: NameShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
func area() ->Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
var squareTest = Square(sideLength: 3.2, name: "subclass test")
squareTest.area() //10.24
squareTest.simpleDescription() //"A square with sides of length 3.2."
squareTest.name //"subclass test"
同时需要注意:
1.子类可以设置自己声明的属性 2.子类可以改变在父类中定义的属性; 3.子类可以调用父类的方法,比如上面构造器方法 init;
- getter 和 setter
除了存储属性,其它属性可以有一个getter
和一个setter
方法
class EquilateralTriangle: NameShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return sideLength*3.0
}
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) //"9.3"
triangle.perimeter = 9.9
print(triangle.sideLength) //"3.3"
- 在
perimeter
的setter
方法中,perimeter
的新值有个默认名字newValue
,你也可以在set
之后明确的指定一个名字,把名字放在()
中,例如:set(perimeter) { sideLength = perimeter / 3.0}
。 - 从上面的
get
与set
方法和OC
的方法有很大的区别,我们可以试着和OC
"相似"的方法来实现sideLength
的get
与set
方法:
class EquilateralTriangleOne: NameShape {
init(sideLength: Double, name: String) {
self.tempLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var tempLength: Double = 0.0
var sideLength: Double {
get {
print("getget")
return self.tempLength
}
set {
print("setset")
self.tempLength = newValue
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(self.sideLength)."
}
}
var triangleOne = EquilateralTriangleOne(sideLength: 3.5, name: "b triangle")
print(triangleOne.sideLength) // getget 3.5
triangleOne.sideLength = 3.6 // setset
print(triangleOne.sideLength) // getget 3.6
- willSet 和 didSet
如果你不需要计算一个属性,但是仍需要在这个属性被设置新值之前
和之后
,执行一些代码(暂且称为代码A),那么可以使用willSet
和didSet
。在 构造器 之外,只要这个属性的值发生改变,代码A 都会被执行,类似观察者模式中的property observe
:
class TriangleAndSquare {
var triangleL: EquilateralTriangle {
willSet {
print("triangleL willSet")
squareL.sideLength = newValue.sideLength
}
didSet {
print("triangleL didSet")
}
}
var squareL: Square {
willSet {
print("squareL willSet")
triangleL.sideLength = newValue.sideLength
}
didSet {
print("squareL didSet")
}
}
init(size: Double, name:String) {
// 少初始化任何一个对象,都会报错
// return from initializer without initializing all stored properties
// 类似于 oc 的用来存储数据的 model,需要对象序列化一样
squareL = Square(sideLength: size, name: name)
triangleL = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 5.0, name: "another shape")
print(triangleAndSquare.squareL.sideLength) // 5.0
print(triangleAndSquare.triangleL.sideLength) // 5.0
triangleAndSquare.squareL = Square(sideLength: 10.0, name: "lager shape") //squareL willSet squareL didSet
print(triangleAndSquare.triangleL.sideLength) // 10.0
- 注意上面的注释部分
- 操作符
?
用操作符?
来表示一个值是可选的,如果?
前面的值是nil
,那么?
后面的所有操作都会被忽视,然后这个表达式的值会变为nil
:
let optionalSquare : Square? = Square(sideLength:5.3, name: "optionalSquare")
var optionalLength = optionalSquare?.sideLength
- 如果
optionalSquare
为nil
,那么就不会调用sideLength
,optionalLength
的值变为nil