IOS開發語言Swift入門連載---繼承

來源:互聯網
上載者:User

標籤:ios   繼承   

IOS開發語言Swift入門連載—繼承

一個類可以繼承(inherit)另一個類的方法(methods),屬性(property)和其它特性。當一個類繼承其它類時,繼承類叫子類(subclass),被繼承類叫超類(或父類,superclass)。在 Swift 中,繼承是區分「類」與其它類型的一個基本特徵。
  在 Swift 中,類可以調用和訪問超類的方法,屬性和下標指令碼(subscripts),並且可以重寫(override)這些方法,屬性和下標指令碼來最佳化或修改它們的行為。Swift 會檢查你的重寫定義在超類中是否有匹配的定義,以此確保你的重寫行為是正確的。
  可以為類中繼承來的屬性添加屬性觀察器(property observer),這樣一來,當屬性值改變時,類就會被通知到。可以為任何屬性添加屬性觀察器,無論它原本被定義為儲存型屬性(stored property)還是計算型屬性(computed property)。
 

定義一個基類(Base class)

  不繼承於其它類的類,稱之為基類(base calss)。
  注意:
  中的類並不是從一個通用的基類繼承而來。如果你不為你定義的類指定一個超類的話,這個類就自動成為基類。
  下面的例子定義了一個叫Vehicle 的基類。這個基類聲明了兩個對所有車輛都通用的屬性(numberOfWheels 和maxPassengers )。這些屬性在description 方法中使用,這個方法返回一個String 類型的,對車輛特徵的描述:

class Vehicle {    var numberOfWheels: Int    var maxPassengers: Int    func description() -> String {        return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"    }    init() {        numberOfWheels = 0        maxPassengers = 1    }}

  Vehicle 類定義了構造器(initializer)來設定屬性的值。構造器會在構造過程一節中詳細介紹,這裡我們做一下簡單介紹,以便於講解子類中繼承來的屬性如何被修改。  構造器用於建立某個類型的一個新執行個體。儘管構造器並不是方法,但在文法上,兩者很相似。構造器的工作是準備新執行個體以供使用,並確保執行個體中的所有屬性都擁有有效初始化值。  構造器的最簡單形式就像一個沒有參數的執行個體方法,使用init 關鍵字:

init() {    // 執行構造過程}

  如果要建立一個Vehicle類的新執行個體,使用構造器文法調用上面的初始化器,即類名後面跟一個空的小括弧:

let someVehicle = Vehicle()

  這個Vehicle 類的構造器為任意的一輛車設定一些初始化屬性值(numberOfWheels = 0 和maxPassengers = 1 )。  Vehicle 類定義了車輛的共同特性,但這個類本身並沒太大用處。為了使它更為實用,你需要進一步細化它來描述更具體的車輛。  子類產生(Subclassing)  子類產生(Subclassing)指的是在一個已有類的基礎上建立一個新的類。子類繼承超類的特性,並且可以最佳化或改變它。你還可以為子類添加新的特性。  為了指明某個類的超類,將超類名寫在子類名的後面,用冒號分隔:

class SomeClass: SomeSuperclass {    // 類的定義}

  下一個例子,定義一個更具體的車輛類叫Bicycle 。這個新類是在Vehicle 類的基礎上建立起來。因此你需要將Vehicle 類放在 Bicycle 類後面,用冒號分隔。  我們可以將這讀作:  “定義一個新的類叫Bicycle ,它繼承了Vehicle 的特性”;

class Bicycle: Vehicle {    init() {        super.init()        numberOfWheels = 2    }}

  previewBicycle 是Vehicle 的子類,Vehicle 是Bicycle 的超類。新的Bicycle 類自動獲得Vehicle 類的特性,比如 maxPassengers 和numberOfWheels 屬性。你可以在子類中定製這些特性,或添加新的特性來更好地描述Bicycle 類。  類定義了一個構造器來設定它定製的特性(單車只有2個輪子)。Bicycle 的構造器調用了它父類Vehicle 的構造器 super.init() ,以此確保在Bicycle 類試圖修改那些繼承來的屬性前Vehicle 類已經初始化過它們了。  注意:  不像 Objective-C,在 Swift 中,初始化器預設是不繼承的,見初始化器的繼承與重寫  Vehicle 類中maxPassengers 的預設值對單車來說已經是正確的,因此在Bicycle 的構造器中並沒有改變它。而numberOfWheels 原來的值對單車來說是不正確的,因此在初始化器中將它更改為 2。  Bicycle 不僅可以繼承Vehicle 的屬性,還可以繼承它的方法。如果你建立了一個Bicycle 類的執行個體,你就可以調用它繼承來的description 方法,並且可以看到,它輸出的屬性值已經發生了變化:

let bicycle = Bicycle()println("Bicycle: \(bicycle.description())")// Bicycle: 2 wheels; up to 1 passengers

  子類還可以繼續被其它類繼承:

class Tandem: Bicycle {    init() {        super.init()        maxPassengers = 2    }}

  上面的例子建立了Bicycle 的一個子類:雙人單車(tandem)。Tandem 從Bicycle 繼承了兩個屬性,而這兩個屬性是Bicycle 從Vehicle繼承而來的。Tandem 並不修改輪子的數量,因為它仍是一輛單車,有 2 個輪子。但它需要修改maxPassengers 的值,因為雙人單車可以坐兩個人。  注意:  子類只允許修改從超類繼承來的變數屬性,而不能修改繼承來的常量屬性。  建立一個Tandem 類的執行個體,列印它的描述,即可看到它的屬性已被更新:

let tandem = Tandem()println("Tandem: \(tandem.description())")// Tandem: 2 wheels; up to 2 passengers

  注意,Tandem 類也繼承了description 方法。一個類的執行個體方法會被這個類的所有子類繼承。  重寫(Overriding)  子類可以為繼承來的執行個體方法(instance method),類方法(class method),執行個體屬性(instance property),或下標指令碼(subscript)提供自己定製的實現(implementation)。我們把這種行為叫重寫(overriding)。  如果要重寫某個特性,你需要在重寫定義的前面加上override 關鍵字。這麼做,你就表明了你是想提供一個重寫版本,而非錯誤地提供了一個相同的定義。意外的重寫行為可能會導致不可預知的錯誤,任何缺少override 關鍵字的重寫都會在編譯時間被診斷為錯誤。  override 關鍵字會提醒 Swift 編譯器去檢查該類的超類(或其中一個父類)是否有匹配重寫版本的聲明。這個檢查可以確保你的重寫定義是正確的。  訪問超類的方法,屬性及下標指令碼  當你在子類中重寫超類的方法,屬性或下標指令碼時,有時在你的重寫版本中使用已經存在的超類實現會大有裨益。比如,你可以最佳化已有實現的行為,或在一個繼承來的變數中儲存一個修改過的值。  在合適的地方,你可以通過使用super 首碼來訪問超類版本的方法,屬性或下標指令碼:  在方法someMethod 的重寫實現中,可以通過super.someMethod() 來調用超類版本的someMethod 方法。  在屬性someProperty 的 getter 或 setter 的重寫實現中,可以通過super.someProperty 來訪問超類版本的someProperty 屬性。  在下標指令碼的重寫實現中,可以通過super[someIndex] 來訪問超類版本中的相同下標指令碼。  重寫方法  在子類中,你可以重寫繼承來的執行個體方法或類方法,提供一個定製或替代的方法實現。  下面的例子定義了Vehicle 的一個新的子類,叫Car ,它重寫了從Vehicle 類繼承來的description 方法:

class Car: Vehicle {    var speed: Double = 0.0    init() {        super.init()        maxPassengers = 5        numberOfWheels = 4    }    override func description() -> String {        return super.description() + "; "            + "traveling at \(speed) mph"    }}

  Car 聲明了一個新的儲存型屬性speed ,它是Double 類型的,預設值是0.0,表示“時速是0英裡”。Car 有自己的初始化器,它將乘客的最大數量設為5,輪子數量設為4。  Car 重寫了繼承來的description 方法,它的聲明與Vehicle 中的description 方法一致,聲明前面加上了override 關鍵字。  Car 中的description 方法並非完全自訂,而是通過super.description 使用了超類Vehicle中的description 方法,然後再追加一些額外的資訊,比如汽車的當前速度。  如果你建立一個Car 的新執行個體,並列印description 方法的輸出,你就會發現描述資訊已經發生了改變:

let car = Car()println("Car: \(car.description())")// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph
重寫屬性

  你可以重寫繼承來的執行個體屬性或類屬性,提供自己定製的getter和setter,或添加屬性觀察器使重寫的屬性觀察屬性值什麼時候發生改變。  重寫屬性的Getters和Setters  你可以提供定製的 getter(或 setter)來重寫任意繼承來的屬性,無論繼承來的屬性是儲存型的還是計算型的屬性。子類並不知道繼承來的屬性是儲存型的還是計算型的,它只知道繼承來的屬性會有一個名字和類型。你在重寫一個屬性時,必需將它的名字和類型都寫出來。這樣才能使編譯器去檢查你重寫的屬性是與超類中同名同類型的屬性相匹配的。  你可以將一個繼承來的唯讀屬性重寫為一個讀寫屬性,只需要你在重寫版本的屬性裡提供 getter 和 setter 即可。但是,你不可以將一個繼承來的讀寫屬性重寫為一個唯讀屬性。  注意:  如果你在重寫屬性中提供了 setter,那麼你也一定要提供 getter。如果你不想在重寫版本中的 getter 裡修改繼承來的屬性值,你可以直接返回super.someProperty 來返回繼承來的值。正如下面的SpeedLimitedCar 的例子所示。  以下的例子定義了一個新類,叫SpeedLimitedCar ,它是Car 的子類。類SpeedLimitedCar 表示安裝了限速裝置的車,它的最高速度只能達到40mph。你可以通過重寫繼承來的speed 屬性來實現這個速度限制:

class SpeedLimitedCar: Car {    override var speed: Double  {    get {        return super.speed    }    set {        super.speed = min(newValue, 40.0)    }    }}

  當你設定一個SpeedLimitedCar 執行個體的speed 屬性時,屬性setter的實現會去檢查新值與限制值40mph的大小,它會將超類的speed 設定為newValue 和40.0 中較小的那個。這兩個值哪個較小由min 函數決定,它是Swift標準庫中的一個全域函數。min 函數接收兩個或更多的數,返回其中最小的那個。  如果你嘗試將SpeedLimitedCar 執行個體的speed 屬性設定為一個大於40mph的數,然後列印description 函數的輸出,你會發現速度被限制在40mph:

let limitedCar = SpeedLimitedCar()limitedCar.speed = 60.0println("SpeedLimitedCar: \(limitedCar.description())")// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph
重寫屬性觀察器(Property Observer)

  你可以在屬性重寫中為一個繼承來的屬性添加屬性觀察器。這樣一來,當繼承來的屬性值發生改變時,你就會被通知到,無論那個屬性原本是如何?的。關於屬性觀察器的更多內容,請看屬性觀察器。  注意:  你不可以為繼承來的常量儲存型屬性或繼承來的唯讀計算型屬性添加屬性觀察器。這些屬性的值是不可以被設定的,所以,為它們提供willSet 或didSet 實現是不恰當。此外還要注意,你不可以同時提供重寫的 setter 和重寫的屬性觀察器。如果你想觀察屬性值的變化,並且你已經為那個屬性提供了定製的 setter,那麼你在 setter 中就可以觀察到任何值變化了。  下面的例子定義了一個新類叫AutomaticCar ,它是Car 的子類。AutomaticCar 表示自動擋汽車,它可以根據當前的速度自動選擇合適的擋位。AutomaticCar 也提供了定製的description 方法,可以輸出當前擋位。

class AutomaticCar: Car {    var gear = 1    override var speed: Double {    didSet {        gear = Int(speed / 10.0) + 1    }    }    override func description() -> String {        return super.description() + " in gear \(gear)"    }}

  當你設定AutomaticCar 的speed 屬性,屬性的didSet 觀察器就會自動地設定gear 屬性,為新的速度選擇一個合適的擋位。具體來說就是,屬性觀察器將新的速度值除以10,然後向下取得最接近的整數值,最後加1來得到檔位gear 的值。例如,速度為10.0時,擋位為1;速度為35.0時,擋位為4:

let automatic = AutomaticCar()automatic.speed = 35.0println("AutomaticCar: \(automatic.description())")// AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4
防止重寫

  你可以通過把方法,屬性或下標指令碼標記為final 來防止它們被重寫,只需要在聲明關鍵字前加上@final 特性即可。(例如:@final var , @final func , @final class func , 以及 @final subscript )  如果你重寫了final 方法,屬性或下標指令碼,在編譯時間會報錯。在擴充中,你添加到類裡的方法,屬性或下標指令碼也可以在擴充的定義裡標記為 final。  你可以通過在關鍵字class 前添加@final 特性(@final class )來將整個類標記為 final 的,這樣的類是不可被繼承的,否則會報編譯錯誤。

IOS開發語言Swift入門連載---繼承

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.