swift學習筆記四

一、方法

1.實例方法和類型方法
結構體、枚舉、類都有實例方法和類型方法。

2.self屬性
類型的每一個實例都有一個隱含屬性self,self完全等于實例本身。事實上,不必要在代碼中經常使用self,不論何時,如果你在一個方法中使用了已知的屬性或者方法名稱,并且沒有明確的寫明self,swift會假定你使用當前的屬性或者方法,當一個方法中的參數名和該實例的方法名相同的時候,需要用self來區分實例的屬性和方法中參數。

3.在實例方法中修改值類型
結構體和枚舉是值類型的,默認情況下,值類型的實例在其方法中是不能修改其屬性。但是,如果你確實想要修改的話,可以為這個方法選擇可變mutating行為,然后就可以改變它的內部屬性,并且這個方法所做的任何改變在方法結束的時候都會寫回到原結構中。

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveByX(deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// 打印 "The point is now at (3.0, 4.0)"

注意:不能在結構體類型的常量(a constant of structure type)上調用可變方法,因為其屬性不能被改變,即使屬性是變量屬性。

4.在可變方法中給self賦值

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

5.類型方法
在方法func前面添加關鍵字static來定義類型方法,或者使用class定義類型方法,標記子類可以復寫父類的類型方法。

在類型方法體中,self指向類型本身而不是它的實例,這意味著可以用self來消除類型屬性和類型方法參數之間的歧義

二、繼承

1.swift中的類并不是從一個通用的基類繼承而來,如果沒有指定一個超類的話,這個類就自動成為一個基類。
2.可以為方法和屬性標記final,也可以在class前面添加final標記這個類不能被繼承。

三、構造過程

1.構造過程是使用類、枚舉、結構體的實例之前的準備過程,在新實例初可用前,必須執行這個過程,具體操作包括設置實例中每個存儲型屬性的初始值和執行其他的必須的設置或初始化工作。通過定義構造器來來實現構造的過程,這些構造器可以看作使用來創建類型新實例的特殊方法,類的實例也可以通過定義析構器在實例釋放之前執行特定的清除工作。(deinit 相當于OC中的dealloc)

2.存儲屬性的初始賦值
類和結構體在創建實例的時候必須為存儲型屬性設置合適的初始值??梢栽跇嬙炱髦袨榇鎯π蛯傩再x值,也可以在定義的時候為存儲型屬性賦值。
注意:當為存儲型屬性設置初始化的時候,或者在析構器中為設置的時候,是直接賦值的,并不會觸發屬性觀察器。

3.自定義構造過程
構造參數

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius 是 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 是 0.0

參數內部名稱和外部名稱
構造器并不像函數和方法那樣在括號前有一個可辨別的名字。因此在調用構造器時,主要通過構造器中的參數名和類型來確定應該被調用的構造器。正因為參數如此重要,如果你在定義構造器時沒有提供參數的外部名字,Swift 會為構造器的每個參數自動生成一個跟內部名字相同的外部名。
可以使用—代替外部參數,表示不需要外部參數名

4.構造過程中常量屬性的修改
可以在構造構成中的任意時間給常量屬性指定一個值,只要再構造過程結束的時候是一個確定的值,一旦常量屬性被賦值,他將永遠不可更改。對于類的實例來說,他的常量屬性只能在定義他的類的構造過程中修改,不能在子類中修改。

5.值類型的構造器代理
構造器可以通過調用其他構造器來完成實例部分的構造過程,這一過程被稱作構造器代理,它能減少多個構造器間的代碼重復。就相當于在自定義初始化的過程調用self.init()

如果自定義了值類型的類的構造方法,那么默認的逐一構造器將不能被調用,如果希望這兩個構造方法都能使用,需要在extension中自定義構造器

6.類的繼承和構造過程
指定構造器和便利構造器
指定構造器是類中最重要的構造器,一個指定構造器將初始化類中的所有屬性,并根據父類鏈往上調用父類的構造器來實現父類的初始化。一個類都至少有一個指定構造器。

便利構造器是類中比較次要的,輔助的構造器。可以定義一個便利構造器來調用同一個類的指定構造器,并為其提供默認值。也可以定義一個便利構造器創建一個有特殊用途或特定輸入值的實例。

//指定構造器
init(parameters) {
       statements
}
//便利構造器
convenience init{
      statements
}

7.類的構造器代理規則
規則一:指定構造器必須調用直接父類的指定構造器super.init()
規則二:便利構造器必須調用同類中定義的其他構造器
規則三:便利構造器必須最終導致一個指定構造器被調用
更簡單的說法:指定構造器必須總是向上代理; 便利構造器必須總是橫向代理

8.兩段式構造過程
swift構造過程中包含了兩個過程。第一個階段,每一個存儲型屬性被引入他們的類指定一個初始值,當每一個存儲型屬性的初始值被指定后,第二個階段開始,它給每個類一次機會,在新的實例沒有使用之前進一步定制他們的存儲型屬性。
兩段式構造過程構造流程展示:
階段一:
一、某個指定構造器或便利構造器被調用。
二、完成新實例內存的分配,但此時內存還沒有被初始化。
三、指定構造器確保其所在類引入的所有存儲型屬性都已賦初值。存儲型屬性所屬的內存完成初始化。
四、指定構造器將調用父類的構造器,完成父類屬性的初始化。
五、這個調用父類構造器的過程沿著構造器鏈一直往上執行,直到到達構造器鏈的最頂部。
六、當到達了構造器鏈最頂部,且已確保所有實例包含的存儲型屬性都已經賦值,這個實例的內存被認為已經完全初始化。此時階段 1 完成。
階段二:
一、從頂部構造器鏈一直往下,每個構造器鏈中類的指定構造器都有機會進一步定制實例。構造器此時可以訪問self、修改它的屬性并調用實例方法等等。
二、最終,任意構造器鏈中的便利構造器可以有機會定制實例和使用self。

9.構造器的繼承和重寫
默認情況下子類并不繼承父類的構造器,但是可以在子類中自定義構造器,當與父類的構造器相同時需要添加override關鍵字

10.構造器的自動繼承
子類默認情況下是不會繼承父類的構造器的,但是在某些特殊情況下,父類的構造器是可以被自動繼承的。
假設你為子類中引入的所有新屬性都提供了默認值,一下2個規則適用:
一、如果子類沒有定義任何指定構造器,它將繼承父類的所有指定構造器
二、子類提供了所有父類指定構造器的實現(無論是通過規則一繼承過來的還是提供了自定義實現),它將自動繼承父類所有的便利構造器。

11.可失敗的構造器

init?() {
    if() { return nil }
}

12.枚舉類型的可失敗構造器

enum TemperatureUnit {
    case Kelvin, Celsius, Fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}
let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
    print("This is a defined temperature unit, so initialization succeeded.")
}
// 打印 "This is a defined temperature unit, so initialization succeeded."

let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
    print("This is not a defined temperature unit, so initialization failed.")
}
// 打印 "This is not a defined temperature unit, so initialization failed."

13.帶有原始值的枚舉類型的可失敗構造器

enum TemperatureUnit: Character {
    case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}

let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
    print("This is a defined temperature unit, so initialization succeeded.")
}
// 打印 "This is a defined temperature unit, so initialization succeeded."

let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
    print("This is not a defined temperature unit, so initialization failed.")
}
// 打印 "This is not a defined temperature unit, so initialization failed."

14.必要構造器

class SomeClass {
    required init() {
        // 構造器的實現代碼
    }
}

15.通過閉包或者函數設定屬性的默認值

class SomeClass {
    let someProperty: SomeType = {
        // 在這個閉包中給 someProperty 創建一個默認值
        // someValue 必須和 SomeType 類型相同
        return someValue
    }()
}

如果某個存儲型屬性的默認值需要一些定制或設置,你可以使用閉包或全局函數為其提供定制的默認值。每當某個屬性所在類型的新實例被創建時,對應的閉包或函數會被調用,而它們的返回值會當做默認值賦值給這個屬性。

這種類型的閉包或函數通常會創建一個跟屬性類型相同的臨時變量,然后修改它的值以滿足預期的初始狀態,最后返回這個臨時變量,作為屬性的默認值。

注意閉包結尾的大括號后面接了一對空的小括號。這用來告訴 Swift 立即執行此閉包。如果你忽略了這對括號,相當于將閉包本身作為值賦值給了屬性,而不是將閉包的返回值賦值給屬性。

注意:如果你使用閉包來初始化屬性,請記住在閉包執行時,實例的其它部分都還沒有初始化。這意味著你不能在閉包里訪問其它屬性,即使這些屬性有默認值。同樣,你也不能使用隱式的self屬性,或者調用任何實例方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 123.繼承 一個類可以從另外一個類繼承方法,屬性和其他特征。當一個類繼承另外一個類時, 繼承類叫子類, 被繼承的...
    無灃閱讀 1,429評論 2 4
  • 本章將會介紹 存儲屬性的初始賦值自定義構造過程默認構造器值類型的構造器代理類的繼承和構造過程可失敗構造器必要構造器...
    寒橋閱讀 780評論 0 0
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,881評論 18 139
  • 構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置實例中每個...
    莽原奔馬668閱讀 699評論 0 3
  • 前幾天看到一則新聞,明星唐嫣在接受記者采訪的時候,回憶說自己4歲開始學琴,唐爸爸為了讓她學好琴,竟然用毛衣針扎她。...
    蒹葭佳人閱讀 366評論 0 0