Swift系列十二 - 继承
2021-04-28 09:48
891 查看
继承是面向对象语言的三大特性之一。
一、继承特性
-
值类型(枚举、结构体)不支持继承,只有类支持继承。
-
没有父类的类,称为基类
Swift并没有像OC、Java那样的规定:任何类最终都要继承自某个基类
子类可以重写父类的下标、方法、属性,重写必须加上
override关键字
二、内存结构
示例代码:
class Animal { var age = 0 } let a = Animal() a.age = 10 print(Mems.size(ofRef: a)) // 输出:32 print(Mems.memStr(ofRef: a)) /* 输出: 0x000000010000c478 0x0000000000000002 0x000000000000000a 0x00027fff84bb8630 */
如果定义一个继承
Animal的类,内存有什么变化呢?
class Dog: Animal { var weight = 0 } let d = Dog() d.age = 10 d.weight = 20 print(Mems.size(ofRef: d)) // 输出:32 print(Mems.memStr(ofRef: d)) /* 输出: 0x000000010000c528 0x0000000000000002 0x000000000000000a 0x0000000000000014 */ // 上面的代码等价于下面的代码 class Dog { var age = 0 var weight = 0 }
一般从父类继承过来的成员内存放在前面,自己的成员内存放在后面。
三、重写
3.1. 重写实例方法、下标
基类示例代码:
class Animal { func< 20000 /span> eat() { print("Animal eat") } subscript(index: Int) -> Int { index } } var animal: Animal animal = Animal() animal.eat() print(animal[0]) /* 输出: Animal eat 0 */
继承重写示例代码:
class Dog: Animal { override func eat() { super.eat() print("Dog eat") } override subscript(index: Int) -> Int { index + 1 } } animal = Dog() animal.eat() print(animal[0]) /* 输出: Animal eat Dog eat 1 */
分析:
animal = Dog()父类指针指向子类对象,体现了多态。重写父类方法使用关键字
override,如果需要执行父类的行为,使用
super。
3.2. 重写类型方法、下标
- 被
class
修饰的类型方法、下标,允许被子类重写 - 被
static
修饰的类型方法、下标,不允许被子类重写
示例代码:
class Animal { class func eat() { print("Animal eat") } class subscript(index: Int) -> Int { index } } Animal.eat() print(Animal[0]) /* 输出: Animal eat 0 */ class Dog: Animal { override class func eat() { super.eat() print("Dog eat") } override class subscript(index: Int) -> Int { super[index] + 1 } } Dog.eat() print(Dog[0]) /* 输出: Animal eat Dog eat 1 */
如果子类和父类都使用
static修饰,直接报错:
如果父类用
class修饰,子类用
static修饰,是可以正常运行的:
3.3. 重写属性
3.3.1 重写实例属性
-
子类可以将父类的属性(存储、计算)重写为计算属性
-
子类不可以将父类属性重写为存储属性
-
只能重写
var
属性,不能重写let
属性 -
重写时,属性名、类型要一致
-
子类重写后的属性权限【不能小于】父类属性的权限
如果父类属性是只读的,那么子类重写后的属性可以是只读的,也可以是可读写的 - 如果父类属性是可读写的,那么子类重写后的属性也必须是可读写的
示例代码:
class Circle { var radius: Int = 0 var diameter: Int { set { print("Circle setDiameter") radius = newValue / 2 } get { print("Circle getDiameter") return radius * 2 } } } var circle: Circle circle = Circle() circle.radius = 6 print(circle.diameter) /* 输出: Circle getDiameter 12 */ circle.diameter = 20 // 输出:Circle setDiameter print(circle.radius) // 输出:10
子类继承示例代码:
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() circle.radius = 12 // 输出:SubCircle setRadius print(circle.diameter) /* 输出: SubCircle getDiameter Circle getDiameter SubCircle getRadius 24 */ circle.diameter = 30 /* 输出: SubCircle setDiameter Circle setDiameter SubCircle setRadius */ print(circle.radius) /* 输出: SubCircle getRadius 15 */
分析:子类调用父类时,本质还是子类在调用,所以父类中的属性
set方法会在子类中查找。
3.3.2 重写类型属性
- 被
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 } } } Circle.radius = 6 print(Circle.diameter) /* 输出: Circle getDiameter 12 */ 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 } } } print(SubCircle.diameter) /* 输出: SubCircle getDiameter Circle getDiameter 12 */ print(SubCircle.radius) // 输出:6
3.4 属性观察器
可以在子类中为父类属性(除了只读计算属性、
let属性)增加属性观察器。
示例代码:
class Circle { var radius: Int = 0 } class SubCircle: Circle { override var radius: Int { willSet { print("SubCircle willSetRadius", newValue) } didSet { print("SubCircle didSetRadius", oldValue, radius) } } } var circle = SubCircle() circle.radius = 10 /* 输出: SubCircle willSetRadius 10 SubCircle didSetRadius 0 10 */
如果父类属性已经添加了属性观察器,子类同样也可以为父类属性添加观察器:
class Circle { var radius: Int = 0 { 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() circle.radius = 10 /* 输出: SubCircle willSetRadius 10 Circle willSetRadius 10 Circle didSetRadius 0 10 SubCircle didSetRadius 0 10 */
子类可以为父类计算属性添加属性观察器:
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) } } } SubCircle.radius = 10 /* 输出: Circle getRadius SubCircle willSetRadius 10 Circle setRadius 10 Circle getRadius SubCircle didSetRadius 20 20 */
为什么首次会输出
Circle getRadius?
其实Circle getRadius获取的就是oldValue,因为只有拿到之前的值,才能设置观察新值的变化。
3.5 final
- 被
final
修饰的方法、下标、属性,禁止被重写; - 被
final
修饰的类,禁止被继承。
相关文章推荐
- Swift系列五 - 可选项
- swift Array map/flatMap/compactMap/filter/reduce/chaining用法小结
- iOS开发之转盘菜单—Swift
- SwiftUI - Grid View 的实现方法,逐步剖析助你实现
- coredata_使用CoreData的Swift / SwiftUI的初学者建议(1)
- 【iOS】【swift】WKWebView与H5之间交互传值
- 【Flutter】flutter与原生交互-swift
- swiftui_在SwiftUI中介绍链接
- 使用OAuthSwift验证Ravelry API
- 使用Xcode生成的接口了解Objective-C与Swift的互操作性
- swift协议接口建立链接_在Swift中创建自己的协议
- 如何在Swift中使用Scene Delegate以编程方式设置您的应用
- swiftui模式_如何在SwiftUI中检测明暗模式
- instagram在中国_在Swift中重新创建Instagram“赞”动画
- macos上的ios虚拟机_如何将中级帖子转换为可在iOS和macOS上运行的SwiftUI应用
- swift 字典 添加元素_在Swift中用字典对数组元素进行分组
- swift 中定义闭包_Swift中的闭包以及如何打破它们……(Pun打算)
- swiftui是什么_为什么SwiftUI使您成为更好的程序员II
- SwiftUI的新应用生命周期以及iOS 14中AppDelegate和SceneDelegate的替代品
- swiftui_SwiftUI中的可扩展按钮