结构、枚举、类
- Struct 和 Enum 在栈上,具有值拷贝语义,不要在里面定义引用类型属性。
- Struct 和 Enum 不支持面向对象,但支持面向协议,适用于轻量级对象。
- Enum 中可以指定 raw value,类型可以是字符、字符串、整数、浮点数。
Enum 一般定义一组相关值成员,可以用 switch-case 处理 Enum。
作为数据模型来说,Struct 比 Class 更加安全、迅速(快很多倍),没有内存泄漏和线程安全的问题。OC 中无法调用 Swift 的 Struct,因为需要继承自 NSObject OC 才可以调用。Struct 亦不能被序列化为 NSData 对象。
总结下:数据模型较小,不会占用太多栈资源;无需继承,且 Swift 提倡面向协议编程;无需储存为 NSData;无需被 OC 调用;在以上情况满足时,强烈建议使用 Struct 而不是 Class。
继承、多态、协议
- 只有类可以继承,子类继承父类属性、方法、下标,实例成员和类型成员都可以继承,子类 is-a 父类,逻辑关系要清楚。
- 使用 final 阻止子类 override 该成员,类上使用 final 意味着该类不能被继承。
- 协议本质是一种声明类型,不能创造实例。
注意:协议变量的内存模型遵从实际变量的内存模型。
可以使用 is 检查类型是否实现了该协议。协议中只能定义变量属性,不能定义常量属性。 -
mutating and required
mutating.png
required.png
字符串和集合
String、Array、Set、Dictionary 都是 Struct,其中 String 内存模型稍稍复杂一点,其他三位都是栈中储存一个指针指向真正的对象,那为什么说他们是值类型 Struct 呢?因为他们都是值语义。
String 内存模型.png
-
String 是一个拥有三个元素的 Struct,有一个指针指向字符串。
这四位都遵循 copy-on-write 技术,当有人拷贝他们时,只是拷贝了他们的指针,只有当真正的值被更改时,才会复制原来的值到另外一个内存并更改。这样就节省了大量的资源。在程序中,我们尽量不要做无谓的更改,提升效率。
String 和 Array 都遵循 capacity 的内存分配规则,当容量超过 capacity 时,重新分配内存的代价很大,影响性能,所以最好一开始预估好 capacity,避免增长。
capacity.png - Dictionary 和 Set 都没有 capacity 的概念,但是相对应的 key 和元素都必须有哈希值,支持 Hashable 协议。
Dictionary 是一个无序的 key-value 集合,key 唯一,value 可重复;
Set 是一个无序的集合,储存的值不可以重复。
第二周作业
第二周作业题目.png我的答案
import UIKit
import Foundation
//交通工具类
class Jiaotong {
var v: Double
var w: Double
init(v: Double, w: Double) {
self.v = v
self.w = w
}
func move(time: Double, v: Double) {
let l = time*v
print("移动距离\(l)")
}
deinit {
print("Over")
}
}
//颜色枚举
enum Color {
case white
case blue
case yellow
case black
case green
case red
}
//火车类继承交通工具
class Train: Jiaotong {
var color: Color
var chexiang = ["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]
init(color: Color) {
self.color = color
super.init(v: 80.0, w: 800.0)
}
//便捷初始化器
convenience init() {
self.init(color: .white)
}
//定义下标
subscript (i: Int) -> String {
get {
return chexiang[i]
}
set {
chexiang[i] = newValue
}
}
//重写父类移动方法
override func move(time: Double, v: Double) {
super.move(time: time, v: v)
print("嗡嗡")
}
}
//飞机的机长结构
struct Captain {
let name: String
var worktime: Double
init(name: String, worktime: Double) {
self.name = name
self.worktime = worktime
print("The aircraft's captain is \(self.name), he worktime is \(self.worktime) hours.")
}
mutating func addWorktime(newWorktime: Double) {
self.worktime += newWorktime
print("The aircraft's captain is \(self.name), he worktime is \(self.worktime) hours.")
}
}
//飞机类继承交通工具
class Aircraft: Jiaotong {
var color: Color
var captain: Captain
//使用可选类型定义初始化器
init?(color: Color, captain: Captain) {
//当机长姓名为空时,初始化失败返回 nil
if captain.name.isEmpty {
return nil
}
self.captain = captain
self.color = color
super.init(v: 800.0, w: 50.0)
}
//自定义操作符比较这两个类的颜色
static func == (left: Train, right: Aircraft) -> Bool {
if left.color == right.color {
return true
}
return false
}
override func move(time: Double, v: Double) {
super.move(time: time, v: v)
print("呼呼")
}
}
//新建各个类的实例,实现里面的方法
var jiaotong = Jiaotong(v: 0.0, w: 0.0)
var train1 = Train()
var train2 = Train(color: .green)
var captain1 = Captain(name: "Davie", worktime: 1055.5)
var aircraft1 = Aircraft(color: .white, captain: captain1)
jiaotong.move(time: 10, v: 10.5)
train1.move(time: 50.5, v: 135.6)
aircraft1?.move(time: 34.5, v: 800.0)
aircraft1?.captain.addWorktime(newWorktime: 10.5)
//用下标遍历车厢元素
for i in 0...9 {
print(train1[i])
}
//先判断飞机实例是否为空,再比较火车和飞机的实例颜色是否相同
if let aircraftLet = aircraft1{
if train1 == aircraftLet {
print("The train1's color is the same as the aircraft.")
}
else {
print("The train1's color is not the same as the aircraft.")
}
}
else {
print("The aircraft has not been initialized yet.")
}
//可选类型赋值为 nil 可以验证析构器
aircraft1 = nil
网友评论