原創|使用教程|編輯:龔雪|2014-06-11 09:29:57.000|閱讀 5593 次
概述:本文為Swift編程語言中文教程第十三部分,講解Swift繼承的用法,內容包括:定義一個基類、Subclassing(子類化)、重寫(Overriding)、重寫方法、重寫屬性、重寫屬性的Getters和Setters、重寫屬性觀察器(Property Observer)、防止重寫等。Swift是蘋果公司在WWDC2014發布的一門編程語言,與Objective-C相比,對學習新手比較友好?;鄱伎丶W根據官方教程以及網上中文資源整理了Swift編程語言中文教程,希望幫助想要學習Swift的朋友,由于技術有限,可能有不足的地方,希望大家指正。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
一個類可以繼承另一個類的方法,屬性和其它特性。當一個類繼承其它類,繼承類叫子類,被繼承類叫超類(或父類)。在Swift中,繼承是區分「類」與其它類型的一個基本特征。
在Swift中,類可以調用和訪問超類的方法,屬性和下標,并且可以重寫(override)這些方法,屬性和下標來優化或修改它們的行為。Swift會檢查你的重寫定義在超類中是否有匹配的定義,以此確保你的重寫行為是正確的。
可以為類中繼承來的屬性添加屬性觀察器(property observer),這樣一來,當屬性值改變時,類就會被通知到。可以為任何屬性添加屬性觀察器,無論它原本被定義為存儲型屬性(stored property)還是計算型屬性(computed property)。
不繼承于其它類的類,稱之為基類。
注意:Swift中的類并不是從一個通用的基類繼承而來。如果你不為你定義的類指定一個超類的話,這個類就自動成為基類。
下面的例子定義了一個叫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() { // perform some initialization here }
如果要創建一個Vehicle類的新實例,使用初始化器語法調用上面的初始化器,即類名后面跟一個空的小括號:
let someVehicle = Vehicle()
這個Vehicle類的初始化器為任意的一輛車設置一些初始化屬性值(numberOfWheels = 0和maxPassengers = 1)。
Vehicle類定義了車輛的共同特性,但這個類本身并沒太大用處。為了使它更為實用,你需要進一步細化它來描述更具體的車輛。
subclassing指的是在一個已有類的基礎上創建一個新的類。子類繼承超類的特性,并且你可以優化或改變它。你還可以為子類添加新的特性。
為了指明某個類的超類,將超類名寫在子類名的后面,用冒號分隔:
class SomeClass: SomeSuperclass { // class definition goes here }
下一個例子,定義一個更具體的車輛類叫Bicycle。這個新類是在Vehicle類的基礎上創建起來。因此你需要將Vehicle類放在Bicycle類后面,用冒號分隔。
我們可以將這讀作:
“定義一個新的類叫Bicycle,它繼承了Vehicle的特性”;
class Bicycle: Vehicle { init() { super.init() numberOfWheels = 2 } }
Bicycle是Vehicle的子類,Vehicle是Bicycle的超類。新的Bicycle類自動獲得Vehicle類的特性,比如maxPassengers和numberOfWheels屬性。你可以在子類中定制這些特性,或添加新的特性來更好地描述Bicycle類。
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方法。一個類的實例方法會被這個類的所有子類繼承。
子類可以為繼承來的實例方法(instance method),類方法(class method),實例屬性(instance property),或下標(subscript)提供自己定制的實現(implementation)。我們把這種行為叫重寫(overriding)。
如果要重寫某個特性,你需要在重寫定義的前面加上override關鍵字。這么做,你就表明了你是想提供一個重寫版本,而非錯誤地提供了一個相同的定義。意外的重寫行為可能會導致不可預知的錯誤,任何缺少override關鍵字的重寫都會在編譯時被診斷為錯誤。
override關鍵字會提醒Swift編譯器去檢查該類的超類(或其中一個父類)是否有匹配重寫版本的聲明。這個檢查可以確保你的重寫定義是正確的。
當你在子類中重寫超類的方法,屬性或下標時,有時在你的重寫版本中使用已經存在的超類實現會大有裨益。比如,你可以優化已有實現的行為,或在一個繼承來的變量中存儲一個修改過的值。
在合適的地方,你可以通過使用super前綴來訪問超類版本的方法,屬性或下標:
在子類中,你可以重寫繼承來的實例方法或類方法,提供一個定制或替代的方法實現。
下面的例子定義了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,或添加屬性觀察器使重寫的屬性觀察屬性值什么時候發生改變。
你可以提供定制的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.0 println("SpeedLimitedCar: \(limitedCar.description())") // SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph
你可以在屬性重寫中為一個繼承來的屬性添加屬性觀察器。這樣一來,當繼承來的屬性值發生改變時,你就會被通知到,無論那個屬性原本是如何實現的。關于屬性觀察器的更多內容,請看屬性觀察器。
注意:你不可以為繼承來的常量存儲型屬性或繼承來的只讀計算型屬性添加屬性觀察器。這些屬性的值是不可以被設置的,所以,為它們提供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.0 println("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的,這樣的類是不可被繼承的,否則會報編譯錯誤。
本文資源來自互聯網,由本網整理編輯,供大家學習參考。因為技術有限,可能會有不足及錯誤,請大家指正。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn