100 Days of Swift - Day 10 - 类Classes

100 Days of Swift - Day 10 - 类Classes

10.0 摘要

  1. 类和结构类似,都可以使用属性和方法创建自己的类型。
  2. 类可以继承,并获得父类的所有属性和方法。
  3. 用final关键字标记一个类,其他类无法继承。
  4. 方法重写允许子类用新的实现替换父类中的方法。
  5. 当两个变量指向同一个类实例时,它们指向同一块内存,——改变一个会改变另一个。
  6. 类有一个析构函数,在类的实例销毁时运行。
  7. 类不同于结构体那样强地强制常量,如果属性声明为变量,则无论如何创建类实例,都可以更改它。

10.1 创建自定义类

  • 类和结构体类似,可以创建新的数据结构,拥有属性和方法。
  1. 类可以继承,而结构体无法继承。
  2. 结构体拥有默认成员初始化构造器,而类没有默认成员初始化构造器,需要创建自定义初始化构造器。
  3. Copy结构体属于深copy,每次都会创建一个新变量,而类的copy 默认是浅copy指向源数据,不会开辟新的内存。
  4. 类有析构函数,在对象被销毁时调用,而结构体没有。
  5. 类的常亮实例对象可以随意修改属性变量,而结构体常量不可以修改其属性变量。
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!
  • 子类重载makeNoise方法
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
    }
}
  • OC 不支持final

10.5 Copying objects

  • 结构体和类的copy有所不同,
  1. 类对象的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
  1. 结构体对象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
  1. 结构体是值类型,而类是引用类型。可根据不同场景选择使用。

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!
}
  1. 结构体是值类型,存储在栈区,由系统管理生命周期,copy一次产生一个新对象,使用完系统自动回收。
    而类是引用类型,由ARC 管理生命周期,copy一次引用计数加一,销毁一次则引用计数减一。直至引用计数为0时执行析构函数,被系统回收。

10.7 可变能力Mutability

  1. 类变量可以随意修改其属性变量,即便类对象是常量类型
  2. 结构体变量不可以随意修改其属性变量,如需修改属性变量需要用mutating关键字修饰方法,编译器则允许该方法可修改属性变量。
class Singer {
    var name = "Taylor Swift"
}
let taylor = Singer()
// 常量类对象修改属性变量
taylor.name = "Ed Sheeran"
print(taylor.name)
// 类对象禁止修改常量属性
class Singer {
    let name = "Taylor Swift"
}

声明:本文创作来自hackingwithswift

你可能感兴趣的:(100 Days of Swift - Day 10 - 类Classes)