Swift第五章 方法、下标、继承
方法(Method)
- 枚举、结构体、类都可以定义实例方法、类型方法
- 实例方法(Instance Method):通过实例对象调用
-
类型方法(Type Method):通过类型调用,用static或者class关键字定义
class Car { static var cout = 0 init() { Car.cout += 1 } //类型方法 static func getCount() -> Int { cout } } let c0 = Car() let c1 = Car() let c2 = Car() print(Car.getCount()) // 3 - self
- 在实例方法中代表实例对象
- 在类型方法中代表类型
- 在类型方法static func getCount中
- cout等价于self.cout、Car.self.cout、Car.cout
mutating
- 结构体和枚举是值类型,默认情况下,值类型的属性不能被自身的实例方法修改
- 在func关键字前加mutating可以允许这种修改行为
struct Point {
var x = 0.0, y = 0.0
//如果不加mutating,会报错,因为x,y为实例值类型的属性;如果当前是类class,可以修改。
mutating func moveBy(deltaX: Double, deltaY: Double) {
x += deltaX
y += deltaY
// self = Point(x: x + deltaX, y: y + deltaY)
}
}
enum StateSwitch {
case low, middle, high
//每次调用next多会改变枚举值
//如果不加mutating,会报错,因为low,middle,high为实例值类型的属性
mutating func next() {
switch self {
case .low:
self = .middle
case .middle:
self = .high
case .high:
self = .low
}
}
}
@discardableResult
-
在func前面加个@discardableResult,可以消除:函数调用后返回值未被使用的警告⚠
struct Point { var x = 0.0, y = 0.0 @discardableResult mutating func moveX(deltaX: Double) -> Double { x += deltaX return x } } var p = Point() p.moveX(deltaX: 10) @discardableResult func get() -> Int { return 10 } get()
下标(subscript)
- 使用subscript可以给任意类型(枚举、结构体、类)增加下标功能,有些地方也翻译为:下标脚本
-
subscript的语法类似于实例方法、计算属性,本质就是方法(函数)
class Point { var x = 0.0, y = 0.0 //定义一个下标 subscript(index: Int) -> Double { set { if index == 0 { x = newValue } else if index == 1 { y = newValue } } get { if index == 0 { return x } else if index == 1 { return y } return 0 } } } var p = Point() //调用下标,设置值 p[0] = 11.1 p[1] = 22.2 print(p.x) // 11.1 print(p.y) // 22.2 //获取下标值 print(p[0]) // 11.1 print(p[1]) // 22.2 - subscript中定义的返回值类型决定了
- get方法的返回值类型
- set方法中newValue的类型
- subscript可以接受多个参数,并且类型任意
下标细节
-
subscript可以没有set方法,但必须要有get方法
class Point { var x = 0.0, y = 0.0 subscript(index: Int) -> Double { get { if index == 0 { return x } else if index == 1 { return y } return 0 } } } -
如果只有get方法,可以省略get
class Point { var x = 0.0, y = 0.0 //get方法的省略 subscript(index: Int) -> Double { if index == 0 { return x } else if index == 1 { return y } return 0 } } -
可以设置参数标签
class Point { var x = 0.0, y = 0.0 subscript(index i: Int) -> Double { if i == 0 { return x } else if i == 1 { return y } return 0 } } var p = Point() p.y = 22.2 print(p[index: 1]) // 22.2 -
下标可以是类型方法
class Sum { //设置类方法下标 static subscript(v1: Int, v2: Int) -> Int { return v1 + v2 } } print(Sum[10, 20]) // 30
结构体、类作为返回值对比
//返回值为class
class Point {
var x = 0, y = 0
}
class PointManager {
var point = Point()
subscript(index: Int) -> Point {
//返回值为class,则不用实现set方法,pm[0].x = 11不会报错
get { point }
}
}
//返回值为struct
struct Point {
var x = 0, y = 0
}
class PointManager {
var point = Point()
subscript(index: Int) -> Point {
//必须实现,否则无法赋值,pm[0].x = 11会报错
set { point = newValue }
get { point }
}
}
var pm = PointManager()
pm[0].x = 11
pm[0].y = 22
// Point(x: 11, y: 22)
print(pm[0])
// Point(x: 11, y: 22)
print(pm.point)
接收多个参数的下标
class Grid {
var data = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]
subscript(row: Int, column: Int) -> Int {
set {
guard row >= 0 && row < 3 && column >= 0 && column < 3 else {
return
}
data[row][column] = newValue
}
get {
guard row >= 0 && row < 3 && column >= 0 && column < 3 else {
return 0
}
return data[row][column]
}
}
}
var grid = Grid()
grid[0, 1] = 77
grid[1, 2] = 88
grid[2, 0] = 99
print(grid.data)
继承
- 值类型(枚举、结构体)不支持继承,只有类支持继承
- 没有父类的类,称为:基类
- Swift并没有像OC、Java那样的规定:任何类最终都要继承自某个基类
- 子类可以重写父类的下标、方法、属性,重写必须加上override关键字
重写实例方法、下标
-
举例
class Animal { func speak() { print("Animal speak") } subscript(index: Int) -> Int { return index } } var anim: Animal anim = Animal() // Animal speak anim.speak() // 6 print(anim[6]) class Cat : Animal { override func speak() { super.speak() print("Cat speak") } override subscript(index: Int) -> Int { return super[index] + 1 } } anim = Cat() // Animal speak // Cat speak anim.speak() // 7 print(anim[6])
重写类型方法、下标
- 被class修饰的类型方法、下标,允许被子类重写
- 被static修饰的类型方法、下标,不允许被子类重写
class Animal {
class func speak() {
print("Animal speak")
}
class subscript(index: Int) -> Int {
return index
}
}
// Animal speak
Animal.speak()
// 6
print(Animal[6])
class Cat : Animal {
override class func speak() {
super.speak()
print("Cat speak")
}
override class subscript(index: Int) -> Int {
return super[index] + 1
}
}
// Animal speak
// Cat speak
Cat.speak()
// 7
print(Cat[6])
重写属性
- 子类可以将父类的属性(存储、计算)重写为计算属性
- 子类不可以将父类属性重写为存储属性
- 只能重写var属性,不能重写let属性
- 重写时,属性名、类型要一致
- 子类重写后的属性权限 不能小于 父类属性的权限
- 如果父类属性是只读的,那么子类重写后的属性可以是只读的、也可以是可读写的
- 如果父类属性是可读写的,那么子类重写后的属性也必须是可读写的
重写实例属性
-
父类
class Circle { var radius: Int = 0 var diameter: Int { set { print("Circle setDiameter") //如果是子类实例调用,就是调用子类的set方法 radius = newValue / 2 } get { print("Circle getDiameter") //如果是当前实例调用,就是拿到radius,如果是子类实例调用,就是调用子类的get方法 return radius * 2 } } } var circle: Circle circle = Circle() circle.radius = 6 // Circle getDiameter // 12 print(circle.diameter) // Circle setDiameter circle.diameter = 20 // 10 print(circle.radius) -
子类重写属性
class SubCircle : Circle { //全部重写为计算属性 override var radius: Int { set { print("SubCircle setRadius") super.radius = newValue > 0 ? newValue : 0 } get { print("SubCircle getRadius") return super.radius } } override var diameter: Int { set { print("SubCircle setDiameter") super.diameter = newValue > 0 ? newValue : 0 } get { print("SubCircle getDiameter") return super.diameter } } } //注意查看调用栈 circle = SubCircle() // SubCircle setRadius circle.radius = 6 // SubCircle getDiameter // Circle getDiameter // SubCircle getRadius ----此时父类Circle的return radius * 2,获取radius本质是调用当前子类的get方法 // 12 print(circle.diameter) // SubCircle setDiameter // Circle setDiameter // SubCircle setRadius---同理radius = newValue / 2,本质调用当前子类的set方法 circle.diameter = 20 // SubCircle getRadius // 10 print(circle.radius)
重写类型属性
- 被class修饰的计算类型属性,可以被子类重写
- 被static修饰的类型属性(存储、计算),不可以被子类重写
class Circle {
static var radius: Int = 0
class var diameter: Int {
set {
print("Circle setDiameter")
radius = newValue / 2
}
get {
print("Circle getDiameter")
return radius * 2
}
}
}
class SubCircle : Circle {
override static var diameter: Int {
set {
print("SubCircle setDiameter")
super.diameter = newValue > 0 ? newValue : 0
}
get {
print("SubCircle getDiameter")
return super.diameter
}
}
}
Circle.radius = 6
// Circle getDiameter
// 12
print(Circle.diameter)
// Circle setDiameter
Circle.diameter = 20
// 10
print(Circle.radius)
SubCircle.radius = 6
// SubCircle getDiameter
// Circle getDiameter
// 12
print(SubCircle.diameter)
// SubCircle setDiameter
// Circle setDiameter
SubCircle.diameter = 20
// 10
print(SubCircle.radius)
属性观察器
-
可以在子类中为父类属性(除了只读计算属性、let属性)增加属性观察器
class Circle { var radius: Int = 1 } class SubCircle : Circle { override var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } var circle = SubCircle() // SubCircle willSetRadius 10 // SubCircle didSetRadius 1 10 circle.radius = 10 -
父类存在属性观察器,子类也可以重写
class Circle { var radius: Int = 1 { willSet { print("Circle willSetRadius", newValue) } didSet { print("Circle didSetRadius", oldValue, radius) } } } class SubCircle : Circle { override var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } var circle = SubCircle() // SubCircle willSetRadius 10 // Circle willSetRadius 10 // Circle didSetRadius 1 10 // SubCircle didSetRadius 1 10 circle.radius = 10 -
父类如果是计算属性,子类可以添加属性观察器
class Circle { var radius: Int { set { print("Circle setRadius", newValue) } get { print("Circle getRadius") return 20 } } } class SubCircle : Circle { override var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } var circle = SubCircle() // Circle getRadius // SubCircle willSetRadius 10 // Circle setRadius 10 // Circle getRadius // SubCircle didSetRadius 20 20 circle.radius = 1 -
父类是类型计算属性
class Circle { class var radius: Int { set { print("Circle setRadius", newValue) } get { print("Circle getRadius") return 20 } } } class SubCircle : Circle { override static var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } // Circle getRadius // SubCircle willSetRadius 10 // Circle setRadius 10 // Circle getRadius // SubCircle didSetRadius 20 20 SubCircle.radius = 10
final
- 被final修饰的方法、下标、属性,禁止被重写
- 被final修饰的类,禁止被继承