在這一章節(jié)中,我們會更深入的了解Swift,蘋果公司給開發(fā)者提供了一系列的方法和類,也就是常說的framework(框架),這些框架叫做Foundation。你可以從developer.apple.com上找到更多關于蘋果公司框架的知識。然而,這些框架也有不夠用的時候,這就需要你能夠編寫你自己的類(class)或方法(methods)。在這一章節(jié)中,我就學習如何編寫你的自己的類(class)、對象(objects)和方法(methods)。掌握這些技能會讓你制作更廣泛的應用程序。
方法(Methods)
方法(Methods)是為了完成一個具體目標而組織在一起的一系列步驟。方法(Methods)和函數(shù)(functions)這兩個概念非常相似。方法(Methods)是在一個類或者一個對象中,為完成一個目標組合在一起的一組步驟,而函數(shù)(functions)是為完成一個目標組合在一起的一組步驟,是獨立存在的。這兩個概念非常相似,成了同義詞。我會經(jīng)常聽到人們在使用這兩個單詞時常?;Q使用,甚至是他們想說的是一個方法,卻使用了function函數(shù)這個單詞。
能夠編寫自己的方法可以非常方便地代替一些重復的工作。如果你想寫一個每天迎接造成的方法,會是這樣子:
func goodMorning ( ) {
println("Good Morning")
}
首先用func作為方法的開頭,func用來聲明新方法的開頭,接著就是方法的名字,使用駝峰命名法命名。例如:
goodMorning( )
Page 97
方法名字后面跟著一對括號,接著就是左大括號,表示一個方法的開始,最后是右大括號,表示一個方法的結束。
為了能夠提供一個更詳細的決策過程,方法(Methods)可以接收外來的輸入值(就是參數(shù)值)。例如,你要訓練一個田徑隊,如果能夠告訴你的運動員他們需要跑具體多遠,可能會比較有幫助(跑步或者跑7英里)。
外來是輸入值會改變最終的結果。這些外來的輸入值叫做parameters(參數(shù))。參數(shù)是外來的值,被傳入到方法中。參數(shù)的名字和類型寫在括號內(nèi),傳入的參數(shù)的值也就是這些括號內(nèi)的變量名的值。例如:
func goodMorning(name: String){
println("Good Morning \(name)")
}?
//Good Morning NAME
先寫參數(shù)名字,然后是冒號,冒號后面就是參數(shù)的類型,如果方法有多個參數(shù),用逗號間隔每個參數(shù):
func goodMorning(name: String, day: String){
println("Good Morning \(name), Happy \(day)")
}
//Good Morning NAME-VARIABLE-HERE, happy DAY-VARIABLE-HERE
在你的方法中,你可以想寫多少代碼就寫多少代碼,不過基于最佳實踐原則,最好把相似功能的代碼寫成一個方法,然后使用時再調(diào)用它。把你的代碼變成多個可重復使用的小方法,這個好習慣,會讓你的更新代碼時輕松不少。
你剛剛編寫了goodMorning方法,但是如何使用這個方法呢?調(diào)用(calling)方法是指,一行可以觸發(fā)方法執(zhí)行的代碼。調(diào)用方法非常簡單,寫下方法的名字后跟一對括號。及時你的括號里并沒有參數(shù),這對括號也要寫上。例如,這個名字為goodNight的方法:
func goodNight () {
println("Good Night")
}
調(diào)用這個方法的代碼是這樣的:
goodNight()
// "Good Night"
Page 98 | Chapter 4 : Diving Deeper
這樣就能調(diào)用goodNight了,執(zhí)行goodNight里的步驟。但是如果你的方法有參數(shù)值,像是goodMorning,如果調(diào)用呢?有參數(shù)值的方法一般都長這樣:
func goodMorning(name: String, day: String){
println("Good Morning \(name), Happy \(day)")
}
//Good Morning NAME-VARIABLE-HERE, happy DAY-VARIABLE-HERE
調(diào)用goodMorning方法的代碼是這樣的:
goodMorning("Steve", day: "Saturday")
//Good Morning Steve, Happy Saturday
最后,如果你的方法有參數(shù),但是調(diào)用的時候忘記提供參數(shù)了,你可以為這些參數(shù)設置默認值。如果在調(diào)用時沒有提供參數(shù),就會使用默認值作為執(zhí)行時的變量值。是這樣設置默認值的:首先在類型后面寫一個等號,然后等號右邊寫上這個默認值。例如,下面的代碼把name和day的默認值設置成“World”和“Day”:
func goodMorning(name: String = "World", day: String = "Day") {
println("Good Morning \(name), Happy \(day)")
}
現(xiàn)在,調(diào)用時忘記提供參數(shù)值,方法中打印出的信息仍然是可讀的:
goodMoring()
// Good Morning World, Happy Day
返回值(Return Values)
除了能夠接收輸入值,執(zhí)行一系列步驟,方法(Methods)還能做更多事情,還能產(chǎn)生輸出值。當一個方法提供了一個輸出值,這個輸出值叫做返回值(return value)。返回值是方法的最終結果,返回給調(diào)用者。一個返回值可以是任何類型的,不過返回值的類型必須在方法中聲明:
func sum(a: Int,b: Int) -> Int {
return a + b
}
如果一個方法有返回值,必須在參數(shù)后面定義一下。返回類型(return type)是被返回來的變量的類型。為了定義返回值的類型,首先要寫一個dash(英文輸入法下的破折號),然后一個大于號,看起來像一個剪頭,表示這個方法有返回值,剪頭的右面是返回值的類型。最后,return關鍵詞還要出現(xiàn)在方法中,return后面是要返回的變量。
Methods | Page 99
不管方法中的代碼有多少行,return表示這個方法結束了,編譯器在編譯方法中的代碼時,遇到return就結束編譯,return后面的代碼就會被忽略掉:
func calculateTip(bill: Float, percentage: Float)-> Float {
var tip = bill * percentage
return tip
}
類(Classes)
假設你是一個建筑師,你剛剛簽了一個合同,要在一個新的小區(qū)修建20個相似的房子。在你派出建筑工隊之前,你必須要畫一個房子的設計圖。這份設計圖將會展現(xiàn)房子的外表和功能。把這份設計圖當做模板,就能制作出20個房子各自的設計圖了。
使用設計圖或者模板來建造物品能夠節(jié)省時間,讓后期維護工作更加簡單。這個原則同樣適用于創(chuàng)建虛擬對象。在Swift中起著設計圖功能的叫做類(class)。類是一個對象(object)的設計圖或模板,這個模板可以反復使用來創(chuàng)建虛擬對象。
一個類定義了對象的屬性和行為。
屬性就是對象具有的特征。屬性(attributes)由properties定義,(properties也有屬性的意思,所以我就用英文了,不知道該怎么翻譯才不會有歧義?。?,properties就是對象中的變量。一個房子的properties可能是外部顏色,街道號碼,浴室的數(shù)量。
行為就是對象提供的方法。例如,方法可能是,把空調(diào)溫度調(diào)整到68華氏度,打開車庫的門,凱琪報警系統(tǒng)。
在Swift中創(chuàng)建你自己的類是非常簡單的。如果你想為你的新房屋建設項目寫一個類,它看起來會是這樣:
class House {
}
類的名字的開頭是大寫英文字母,這樣能讓其他的開發(fā)者區(qū)分出這時一個類還是一個對象。對象和方法常常用一個小寫字母開頭。
屬性(Properties)
給你自定義的類增加屬性和聲明一個變量非常相似。你可以給你的house class增加一些屬性:
class House {
var exteriorColor = "Brown"
var currentAirTemp = 70
var isGarageOpen = true
var isAlarmEnabled = false
}
Page 100 | Chapter 4 : Diving Deeper
你給類增加了4個屬性,每個都設置了默認值。這意味著參數(shù)沒有傳入新值時,從這個類中建造的房子都會有一個褐色的外表,車庫的門是開啟的,報警系統(tǒng)是關閉的,空調(diào)設置的溫度是70華氏度。
方法(Methods)
你也可以給你的類增加一些方法:
class House {
var exteriorColor = "Brown"
var currentAirTemp = 70
var isGarageOpen = false
var isAlarmEnabled = false
func prepareForNighttime(){
isGarageOpen = false
isAlarmEnabled = true
currentAirTemp = 65
}
func prepareForDaytime(){
isGarageOpen = true
isAlarmEnabled = false
currentAirTemp = 70
}
}
創(chuàng)建一個對象(Creating an Object)
現(xiàn)在你已經(jīng)為你的類(house class)定義了屬性和方法,是時候來建造第一個房子了。為了從一個類中創(chuàng)建一個對象,你需要調(diào)用初始化方法(initializer method)。這個初始化方法是專門為了設置新對象而設計的。初始化方法有些像你第一次打開Mac時遇見的安裝向導。
Creating an Object | Page 101
如果你的參數(shù)有默認值,那么就沒有必要寫初始化方法了,Xcode會為你創(chuàng)建一個。初始化方法是這樣寫的,先寫一個類的名字,然后跟上一對括號,例如:
var myHouse: House = House()
或者也可寫成這樣:
var myHouse = House()
不管那種方法都可以創(chuàng)建一個新的房子叫做myHouse。
獲取屬性(Accessing Properties)
用點語法可以獲取屬性的值,點語法是可以取值或賦值的格式。點語法始于一個對象:
var myHouse = House()
為了獲取exteriorColor,先寫變量名字,后面跟一個點,然后是exteriorColor:
myHouse.exteriorColor
//Brown
exeriorColor返回是字符串"Brown",因為這個屬性的默認值是"Brown"。
這個簡單的格式也可以用于給屬性賦值,為了賦值,需要增加一個等號,然后寫上新的值:
myHouse.exteriorColor = "Blue"
這樣就把exeriorColor的值改成了"Blue":
myHouse.exteriorColor = "Blue"
println(myHouse.exteriorColor)
//"Blue"
當代碼把exeriorColor的值改成"Blue"后,接下來的一行打印出了房子的exeriorColor值。
Page 102 | Chapter 4 : Diving Deeper
調(diào)用方法(Calling Methods)
調(diào)用house類中的方法直接寫上類的方法名字即可:
myHouse.prepareForNighttime()
調(diào)用方法和之前你看到調(diào)用屬性都是使用點方法。首先,你先寫一個對象的名字,然后一個點,跟著你想調(diào)用的方法的名字,最后是一對括號。如果這個方法有參數(shù),那么寫上參數(shù)值,如果沒有參數(shù),寫一個空著的括號即可。
子類(Subclasses)
當你在創(chuàng)建什么東西的時候,重復使用模板會比重新畫草稿好的多。假設你想建造一個木屋,木屋和房子有很多的相似之處,不過也有一些不同的屬性和行為。這時,你可以借用house類然后做一些改變,而不是去重現(xiàn)畫一個設計圖。這個重新使用的過程就叫做子類化(subclassing)。
子類化能夠使子類和父類之間簡便地分享屬性和行為。在這個例子中,父類是House,而子類是Cabin。寫一個子類和創(chuàng)建一個類差不多,不同的是先有子類的名字,然后一個冒號,父類的名字是在冒號之后。例如:
class Cabin: House {
}
繼承(Inheritance)
繼承是指的父類的屬性和行為能夠傳遞給子類。所有父類的屬性和行為都會自動地傳遞給子類。例如,cabin類繼承了exteriorColor, currentAirTemp, isGarageOpen,和isAlarmEnabled的屬性以及屬性的默認值。cabin類還繼承了prepareForNighttime()和prepareForDaytime()兩個方法。然而,如果有需要,cabin類可以增加或者修改這些屬性值。例如,cabin類可能想把exteriorColor的默認值設置成"Red"。
Subclasses | Page 103
重構重寫(Overriding)
如果你不想要一個褐色的小木屋怎么辦?沒關系,有了重寫(overriding)就可以實現(xiàn)了。在子類中改變繼承來屬性或方法就叫做重寫。重寫使子類可以用用自己的特定的屬性和方法。為了重寫一個方法,我們會在方法前面增加一個override關鍵詞。
初始化重寫(Overriding initializers)
你可以用初始化方法來重寫屬性的默認值。無論什么時候,創(chuàng)建一個新的對象后,都要調(diào)用初始化方法,這意味著你要寫你的初始化方法和默認值:
class House {
var exteriorColor = "Brown"
var currentAirTemp = 70
var isGarageOpen = false
var isAlarmEnabled = false
func prepareForNighttime(){
isGarageOpen = false
isAlarmEnabled = true
currentAirTemp = 65
}
func prepareForDaytime(){
isGarageOpen = true
isAlarmEnabled = false
currentAirTemp = 70
}
}
class Cabin: House {
override init(){
super.init()
exteriorColor = "Red"
}
}
cabin類用init關鍵詞定義了自己的初始化方法。因為cabin類是重寫的House類的初始化方法,所以需要在方法開頭加上override關鍵詞。記住,House類的初始化方法是自動創(chuàng)建的。init關鍵詞后面跟著一對空括號,然后是左大括號,后面寫初始化方法的具體內(nèi)容。
在有子類的情況下,在重現(xiàn)或者修改子類之前,父類的初始化方法要先被調(diào)用。就父類而言,使用super關鍵詞。在子類的init方法中,寫super.init()。這就能夠調(diào)用父類的初始化方法了。一旦完成初始化,子類就可以自由地去重寫和修改了。在這個例子中,cabin類把exteriorColor修改為"Red"。
page 104 | Chapter 4 : Diving Deeper
重寫方法
除了能夠重寫子類的屬性之外,你還可以重寫子類的方法。例如,當你為cabin設置nighttime時,就和House類不太相同。在一個House里,你可能想關上車庫的門,改變空調(diào)的溫度,開啟報警系統(tǒng),然而,在一個cabin里,沒有報警系統(tǒng),也沒有車庫,你更想在壁爐中生火。重新方法需要用到override關鍵詞:
class Cabin: House {
override init(){
super.init()
exteriorColor = "Red"
}
override func prepareForNighttime(){
startFire()
}
}
在這一章中,你了解了更多swift知識,學習了如何創(chuàng)建自己的類和方法,如何創(chuàng)建子類和重寫,有了這些技能,你已經(jīng)能夠編寫任何你需要的類了。你的知識正在變多,現(xiàn)在是時候把這些知識應用到實踐中去了,繼續(xù)我們的Race Car練習吧。