結構、枚舉、類
- 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