100 Days of Swift - Day 10 - 类Classes
10.0 摘要
- 类和结构类似,都可以使用属性和方法创建自己的类型。
- 类可以继承,并获得父类的所有属性和方法。
- 用final关键字标记一个类,其他类无法继承。
- 方法重写允许子类用新的实现替换父类中的方法。
- 当两个变量指向同一个类实例时,它们指向同一块内存,——改变一个会改变另一个。
- 类有一个析构函数,在类的实例销毁时运行。
- 类不同于结构体那样强地强制常量,如果属性声明为变量,则无论如何创建类实例,都可以更改它。
10.1 创建自定义类
- 类和结构体类似,可以创建新的数据结构,拥有属性和方法。
- 类可以继承,而结构体无法继承。
- 结构体拥有默认成员初始化构造器,而类没有默认成员初始化构造器,需要创建自定义初始化构造器。
- Copy结构体属于深copy,每次都会创建一个新变量,而类的copy 默认是浅copy指向源数据,不会开辟新的内存。
- 类有析构函数,在对象被销毁时调用,而结构体没有。
- 类的常亮实例对象可以随意修改属性变量,而结构体常量不可以修改其属性变量。
class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
// 创建类的实例对象和结构体类似,调用初始化方法,传入成员初始值即可
let poppy = Dog(name: "Poppy", breed: "Poodle")
10.2 类继承 Class inheritance
- 类可以通过继承获得父类的所有属性和方法,也可以创建只属于自己的属性和方法。
class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
// Poodle 继承自 Dog,无自定义初始化构造方法
class Poodle: Dog {
}
// 默认可以调用父类初始化方法
let poodle = Poodle(name: "Poodle旺财", breed: "Poodle")
// Poodle 继承自 Dog,自定义初始化构造器,通过super关键字可以调用父类的初始化构造器进行初始化
class Poodle: Dog {
init(name: String) {
super.init(name: name, breed: "Poodle")
}
}
//
let poodle = Poodle(name: "Poodle旺财")
10.3 重载方法
- 子类方法用overriding修饰,覆盖父类方法,自定义实现称之为重载。
class Dog {
func makeNoise() {
print("Woof!")
}
}
// 继承Dog
class Poodle: Dog {
}
// 调用父类方法
let poppy = Poodle()
poppy.makeNoise()
// Woof!
class Poodle: Dog {
override func makeNoise() {
print("Yip!")
}
}
let poppy = Poodle()
poppy.makeNoise()
// Yip!
- 非子类用overriding修饰方法编译器会报错。
- 重载目的是子类复用父类方法并在其基础上扩展,或者子类需要和父类不同的实现。
10.4 Final classes
- 非继承类,类默认可以被继承,从而构建复杂有序的类簇结构,但如果为了保持类简单不可被继承,需要使用final关键字修饰类。
- 非继承类不可重载方法。
final class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
10.5 Copying objects
- 类对象的copy 是浅copy,两个对象内存指向同一区域,一改全改,
class Singer {
var name = "Taylor Swift"
}
var singer = Singer()
print(singer.name)
var singerCopy = singer
singerCopy.name = "Justin Bieber"
print(singer.name)
// Justin Bieber
print(singerCopy.name)
// Justin Bieber
- 结构体对象copy则是深copy,copy出来的对象和源对象属于两个不同的对象,只是数据一样。
struct Singer {
var name = "Taylor Swift"
}
var singer = Singer()
var singerCopy = singer
singerCopy.name = "Justin Bieber"
print(singer.name)
// Taylor Swift
print(singerCopy.name)
// Justin Bieber
- 结构体是值类型,而类是引用类型。可根据不同场景选择使用。
10. 6 析构函数 Deinitializers
- 类有析构函数,而结构体没有,析构函数是类对象生命周期函数之一,当类对象被销毁时调用。
class Person {
var name = "John Doe"
init() {
print("\(name) is alive!")
}
func printGreeting() {
print("Hello, I'm \(name)")
}
}
deinit {
print("\(name) is no more!")
}
for _ in 1...3 {
let person = Person()
person.printGreeting()
// Hello, I'm John Doe
// John Doe is no more!
}
- 结构体是值类型,存储在栈区,由系统管理生命周期,copy一次产生一个新对象,使用完系统自动回收。
而类是引用类型,由ARC 管理生命周期,copy一次引用计数加一,销毁一次则引用计数减一。直至引用计数为0时执行析构函数,被系统回收。
10.7 可变能力Mutability
- 类变量可以随意修改其属性变量,即便类对象是常量类型
- 结构体变量不可以随意修改其属性变量,如需修改属性变量需要用mutating关键字修饰方法,编译器则允许该方法可修改属性变量。
class Singer {
var name = "Taylor Swift"
}
let taylor = Singer()
// 常量类对象修改属性变量
taylor.name = "Ed Sheeran"
print(taylor.name)
// 类对象禁止修改常量属性
class Singer {
let name = "Taylor Swift"
}