1. 多态性
import UIKit
class Avatar { // 角色
var name: String
var life = 100 {
didSet { // 这里一定只能用didSet,在改变之后再次改变life的值,如果用willSet只能在内部改变,出去之后还是原样
if life > 100 {
life = 100
}
}
}
var isAlive: Bool {
return life <= 0 ? false : true
}
init(name: String) {
self.name = name
}
func beAttacked(attack: Int) {
life -= attack
if life < 0 {
life = 0
}
}
}
class User: Avatar {
var score = 0
var level = 0
func getScore(score: Int) {
self.score += score
if score > level * 100 { // 升级
level += 1
}
}
}
final class Magician: User {
var magic = 100
func heal(user: User) { // 魔法师可以给User下面的所有子类治疗
user.life += 200
}
}
class Warrior: User {
var weapon: String? // 可以不拿武器
}
class Monster: Avatar {
func attack(user: User, amount: Int) {
user.beAttacked(attack: amount)
}
}
final class Zombie: Monster { // 僵尸
var type: String = "Default"
}
let player1 = Magician(name: "aaa") // 也是User的对象,也是Avatar的对象
let player2 = Warrior(name: "bbb")
let zombie = Zombie(name: "ccc")
let monster = Monster(name: "ddd")
func printBasicInfo(avatar: Avatar) {
print("名字是\(avatar.name),生命值是\(avatar.life),\(avatar.isAlive == true ? "活着" : "死了")")
}
printBasicInfo(avatar: player1)
printBasicInfo(avatar: player2)
printBasicInfo(avatar: zombie)
printBasicInfo(avatar: monster)
let avatar: [Avatar] = [player1, player2, zombie, monster] // 数组元素的类型是Avatar,可是存放的是Avatar的子类
for avatar in avatar {
avatar.beAttacked(attack: 110)
}
printBasicInfo(avatar: player1)
printBasicInfo(avatar: player2)
printBasicInfo(avatar: zombie)
printBasicInfo(avatar: monster)
player1.heal(user: player1)
player1.heal(user: player2)
print(player1.life)
printBasicInfo(avatar: player1)
printBasicInfo(avatar: player2)
2. 两段式构造
在把所有属性全部初始化之前,不允许有逻辑涉及self自身
Ps,必须先初始化子类自己的属性,再调用父类的构造函数
import UIKit
class A {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
class B: A {
var z: Int
init(x: Int, y: Int, z: Int) {
// 构造初值
self.z = z
super.init(x: x, y: y)
// 构造初值完毕,进行后续逻辑
decX()
}
func decX()
{
x -= 1
}
}
3. 构造函数和普通函数一样是可以有默认参数的,可以在括号里面就给参数赋初值
4. convenience关键字,用于修饰init构造函数,表示该构造函数里面还可以调用该类中其他的构造函数
5. convenience关键字修饰的函数中不允许出现super.init,必须要依靠一个指定的构造函数来实现
6. 构造函数的继承有两个规则
规则一:如果子类实现了父类所有指定构造函数,则自动继承父类的所有便利构造函数
代码如下
import UIKit
class A {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
convenience init(x: Int) {
let y = 6
self.init(x: x, y: y)
}
func printHello() {
print("Hello!")
}
}
class B: A { // B实现了父类的所有指定构造函数,因此B的实例可以调用A的所有指定构造函数和便利构造函数
override init(x: Int, y: Int) {
let xx = 2 * x
let yy = 2 * y
super.init(x: xx, y: yy)
}
}
let b = B(x: 10)
解释,这里传入x为10,用的是父类的便利构造函数,因此先调用父类的便利构造函数,则此时x为10,y为6,由于在函数的最后还写了self.init(x: x, y: y),说明还要调本类中的构造函数,这里的类指的是父类,即A,但是在B中原有的构造函数被重载了,因此调用的其实是重载之后的构造函数,因此全部double啦,变成20和12!
下面来看一段代码
import UIKit
class A {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
convenience init(x: Int) {
let y = 6
self.init(x: x, y: y)
}
init() {
self.x = 100
self.y = 200
}
func printHello() {
print("Hello!")
}
}
class B: A { // B实现了父类的所有指定构造函数,因此B的实例可以调用A的所有指定构造函数和便利构造函数
override init(x: Int, y: Int) {
let xx = 2 * x
let yy = 2 * y
super.init(x: xx, y: yy)
}
}
let b = B(x: 6)
b.x
b.y
我仅仅是在A中又加了一个指定的构造函数init(),传入为空,编译器就开始报错了。
报错的原因在于不满足规则一,B并没有重载A类所有的指定构造函数,A中指定的构造函数有两个,B却只实现了一个,因此,B也不会继承A中其他的便利函数。
如果在B中加入这样几行代码
override init() {
print("Hello!")
super.init()
}
就不报错了,因为这个时候B重写了A所有的指定构造函数,所以也自动继承了A的所有便利构造函数。
Ps:子类指定的构造函数一定要用super.init,不然肯定报错!
规则二:如果子类没有实现(这里的实现我认为是以重载方式去实现)父类的任何指定构造函数,则自动继承父类所有的指定构造函数
代码如下
import UIKit
class A {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
convenience init(x: Int) {
let y = 6
self.init(x: x, y: y)
}
init() {
self.x = 100
self.y = 200
}
func printHello() {
print("Hello!")
}
}
class B: A {
}
let b1 = B()
let b2 = B(x: 1)
let b3 = B(x: 1, y: 2)
这里B没有重载A的任何指定的构造函数,因此自动继承A的所有指定的构造函数,同时,根据规则一,如果子类实现了父类所有的指定构造函数,则自动继承父类的所有便利构造函数,因此你看b2那一行代码也是不报错的
7. 子类制定的构造函数一定要调用super.init,不然一定会报错
8. required 关键字,如果修饰父类的构造函数,表示该类的子类一定要实现(我理解为重载)该构造函数,并且父类和子类的都要用required关键字,子类不能写override。
9. 结构体因为没有继承,所以没有指定的构造函数和便利的构造函数一说。