類(lèi)和結(jié)構(gòu)體
1.Swift中類(lèi)和結(jié)構(gòu)體有很多共同點(diǎn):
- 定義屬性用于存儲(chǔ)值
- 定義方法用于提供功能
- 定義附屬腳本用于訪問(wèn)值
- 定義構(gòu)造器用于生成初始化值
- 通過(guò)擴(kuò)展以增加默認(rèn)實(shí)現(xiàn)的功能
- 實(shí)現(xiàn)協(xié)議以提供某種標(biāo)準(zhǔn)功能
2.與結(jié)構(gòu)體相比,類(lèi)還有如下附加功能:
- 繼承允許一個(gè)類(lèi)繼承另一個(gè)類(lèi)的特征
- 類(lèi)型轉(zhuǎn)換允許在運(yùn)行時(shí)檢查和解釋一個(gè)類(lèi)實(shí)例的類(lèi)型
- 解構(gòu)器允許一個(gè)類(lèi)實(shí)例釋放任何其所被分配的資源
- 引用計(jì)數(shù)允許對(duì)一個(gè)類(lèi)的多次引用
語(yǔ)法定義
類(lèi)和結(jié)構(gòu)體有著類(lèi)似的定義方式徒恋。我們通過(guò)關(guān)鍵字class和struct來(lái)分別表示類(lèi)和結(jié)構(gòu)體希俩,并在一對(duì)大括號(hào)中定義它們的具體內(nèi)容:
class SomeClass {
}
struct SomeStruct {
}
eg:
struct Engine {
var power = 0
var age = 0
}
class Car {
var engine = Engine()
var name:String?
var speed = 0
}
結(jié)構(gòu)體和類(lèi)都適用構(gòu)造器語(yǔ)法來(lái)生成新的實(shí)例忍法。構(gòu)造器語(yǔ)法的最簡(jiǎn)單形式時(shí)在結(jié)構(gòu)體或者類(lèi)的類(lèi)型名稱(chēng)后跟隨一對(duì)空括號(hào)服爷。通過(guò)這種方式所創(chuàng)建的類(lèi)或者結(jié)構(gòu)體實(shí)例药薯,其屬性均會(huì)被初始化為默認(rèn)值您朽。
let engine = Engine()
let car = Car()
屬性訪問(wèn)
1.通過(guò)使用點(diǎn)語(yǔ)法狂丝,我們可以訪問(wèn)實(shí)例的屬性。其語(yǔ)法規(guī)則是哗总,實(shí)例名后面緊跟屬性名几颜,兩者通過(guò)點(diǎn)(.)連接。
2.我們也可以使用點(diǎn)語(yǔ)法為變量屬性賦值讯屈。
print(car.engine.power)
car.engine.power = 86
print(car.engine.power)
結(jié)構(gòu)體類(lèi)型和成員逐一構(gòu)造器
所有的結(jié)構(gòu)體都有一個(gè)自動(dòng)生成的成員逐一構(gòu)造器蛋哭,用于初始化新結(jié)構(gòu)體實(shí)例中成員的屬性。新實(shí)例中各個(gè)屬性的初始值可以通過(guò)屬性的名稱(chēng)傳遞到成員逐一構(gòu)造器之中:
let engine2 = Engine(power: 100,age: 20)
與結(jié)構(gòu)體不同涮母,類(lèi)實(shí)例沒(méi)有默認(rèn)的成員逐一構(gòu)造器谆趾。
結(jié)構(gòu)體和枚舉是值類(lèi)型
值類(lèi)型 被賦予給一個(gè)變量、常量或者被傳遞給一個(gè)函數(shù)的時(shí)候哈蝇,其值會(huì)被拷貝棺妓。
在之前的章節(jié)中,我們已經(jīng)大量的使用了值類(lèi)型炮赦。實(shí)際上怜跑,在Swift中,所有的基本類(lèi)型:整數(shù)吠勘,浮點(diǎn)數(shù)性芬,布爾值,字符串剧防,數(shù)組和字典都是值類(lèi)型植锉,并且在底層都是以結(jié)構(gòu)體的形式所實(shí)現(xiàn)。
在Swift中峭拘,所有的結(jié)構(gòu)體和枚舉類(lèi)型都是值類(lèi)型俊庇。這意味著它們的實(shí)例,以及實(shí)例中所包含的任何值類(lèi)型屬性鸡挠,在代碼中傳遞的時(shí)候都會(huì)被復(fù)制辉饱。
struct Engine {
var power = 0
var age = 0
}
class Car {
var engine = Engine()
var name:String?
var speed = 0
}
var engine = Engine(power: 100,age: 20)
var engine2 = engine
engine2.power = 101
print(engine)
print(engine2)
enum Direction {
case Wast,East,South,North
}
var direction1 = Direction.East
var direction2 = direction1
direction2 = .South
print(direction1)
print(direction2)
類(lèi)是引用類(lèi)型
與值類(lèi)型不同,引用類(lèi)型在被賦予到一個(gè)變量拣展、常量或者被傳遞到一個(gè)函數(shù)時(shí)彭沼,其值不會(huì)被拷貝。因此备埃,引用的是已存在的實(shí)例本身而不是其拷貝姓惑。
let car = Car()
car.name = "BZ"
let car2 = car
car2.name = "DZ"
print(car.name!)
print(car2.name!)
恒等運(yùn)算符
因?yàn)轭?lèi)是引用類(lèi)型褐奴,有可能有多個(gè)常量和變量在幕后同時(shí)引用同一個(gè)類(lèi)的實(shí)例。如果能夠判定兩個(gè)常量或者變量是否引用同一個(gè)類(lèi)實(shí)例將會(huì)很有幫助于毙。為了達(dá)到這個(gè)目的敦冬,Swift內(nèi)建了兩個(gè)恒等運(yùn)算符:
- 等價(jià)于 (===)
- 不等價(jià)于 (!==)
運(yùn)用這兩個(gè)運(yùn)算符檢測(cè)兩個(gè)常量或者變量是否引用同一個(gè)實(shí)例。
note: “等價(jià)于” (用三個(gè)等號(hào)表示望众, ===) 與“等于” (用兩個(gè)等號(hào)表示匪补,==)的不同:
1.“等價(jià)于”表示兩個(gè)類(lèi)類(lèi)型的常量或者變量引用同一個(gè)類(lèi)實(shí)例。
2.“等于”表示兩個(gè)實(shí)例的值“相等”或“相同”烂翰,判定時(shí)要遵照設(shè)計(jì)者定義的評(píng)判標(biāo)準(zhǔn),因此相對(duì)于“相等”來(lái)說(shuō)蚤氏,這是一種更加合適的叫法甘耿。
類(lèi)和結(jié)構(gòu)體的選擇
結(jié)構(gòu)體實(shí)例是通過(guò)值傳遞的,類(lèi)實(shí)例是通過(guò)引用傳遞的竿滨。這意味著兩者適用不同的任務(wù)佳恬。
按照通用的標(biāo)準(zhǔn),當(dāng)符合一條或者多條一下條件時(shí)于游,請(qǐng)考慮使用結(jié)構(gòu)體:
1.該數(shù)據(jù)結(jié)構(gòu)的主要目的是用來(lái)封裝少量相關(guān)簡(jiǎn)單數(shù)據(jù)值毁葱。
2.有理由預(yù)計(jì)該數(shù)據(jù)結(jié)構(gòu)的實(shí)例在被賦值或傳遞時(shí),封裝的數(shù)據(jù)將會(huì)被拷貝而不是被引用贰剥。
3.該數(shù)據(jù)結(jié)構(gòu)中存儲(chǔ)的值類(lèi)型屬性倾剿,也應(yīng)該被拷貝,而不是被引用蚌成。
4.該數(shù)據(jù)結(jié)構(gòu)不需要去繼承另一個(gè)既有類(lèi)型的屬性或者行為前痘。
字符串,數(shù)組和字典類(lèi)型的賦值與復(fù)制行為
Swift中担忧,許多基本類(lèi)型芹缔,如String,Array和Dictionary類(lèi)型均以結(jié)構(gòu)體的形式實(shí)現(xiàn)瓶盛。這意味著被賦值給新的常量或變量最欠,或者被傳入函數(shù)或方法時(shí),它們的值會(huì)被拷貝惩猫。
在OC中芝硬,NSString,NSArray和NSDictionary類(lèi)型均以類(lèi)的形式實(shí)現(xiàn)帆锋,而并非結(jié)構(gòu)體吵取。它們?cè)诒毁x值或者被傳入函數(shù)或方法時(shí),不會(huì)發(fā)生值拷貝锯厢,而是傳遞現(xiàn)有實(shí)例的引用皮官。
屬性
屬性將值跟特定的類(lèi)脯倒、結(jié)構(gòu)體或枚舉關(guān)聯(lián)。存儲(chǔ)屬性存儲(chǔ)常量或變量作為實(shí)例的一部分捺氢,而計(jì)算屬性計(jì)算一個(gè)值藻丢。計(jì)算屬性可用于類(lèi),結(jié)構(gòu)體和枚舉摄乒,存儲(chǔ)屬性只能用于類(lèi)和結(jié)構(gòu)體悠反。
存儲(chǔ)屬性和計(jì)算屬性通常與特定類(lèi)型的實(shí)例關(guān)聯(lián)。但是馍佑,屬性也可以直接作用于類(lèi)型本身斋否,這種屬性稱(chēng)為類(lèi)型屬性。
另外拭荤,還可以定義屬性觀察器來(lái)監(jiān)控屬性值的變化茵臭,以此來(lái)觸發(fā)一個(gè)自定義的操作。屬性觀察器可以添加到自己定義的存儲(chǔ)屬性上舅世,也可以添加到父類(lèi)繼承的屬性上旦委。
存儲(chǔ)屬性
1.簡(jiǎn)單來(lái)說(shuō),一個(gè)存儲(chǔ)屬性就是存儲(chǔ)在特定類(lèi)或結(jié)構(gòu)體實(shí)例里的一個(gè)常量或者變量雏亚。存儲(chǔ)屬性可以是變量存儲(chǔ)屬性缨硝,也可以是常量存儲(chǔ)屬性。
2.可以在定義存儲(chǔ)屬性的時(shí)候指定默認(rèn)值罢低,也可以在構(gòu)造過(guò)程中設(shè)置或修改存儲(chǔ)屬性的值查辩,甚至修改常量存儲(chǔ)屬性的值。
struct FixedLengthRange {
var firstValue:Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
rangeOfThreeItems.firstValue = 6
在上面的例子中奕短,length在創(chuàng)建實(shí)例的時(shí)候被初始化宜肉,因?yàn)樗且粋€(gè)常量存儲(chǔ)屬性,所以之后無(wú)法修改它的值翎碑。
3.常量結(jié)構(gòu)體的存儲(chǔ)屬性
如果創(chuàng)建了一個(gè)結(jié)構(gòu)體的實(shí)例并將其賦值給一個(gè)常量谬返,則無(wú)法修改改實(shí)例的任何屬性,即使定義了變量存儲(chǔ)屬性:
let rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
//因?yàn)榻Y(jié)構(gòu)體是值類(lèi)型日杈,賦值給let常量以后就無(wú)法修改
rangeOfThreeItems.firstValue = 6
這種行為是由于結(jié)構(gòu)體屬于值類(lèi)型遣铝。當(dāng)值類(lèi)型的實(shí)例被聲明為常量的時(shí)候,它的所有屬性也就成了常量莉擒。屬于引用類(lèi)型的類(lèi)(class)則不一樣了酿炸。把一個(gè)引用類(lèi)型的實(shí)例賦值給一個(gè)常量后,仍然可以修改該實(shí)例的變量屬性涨冀。
4.延遲存儲(chǔ)屬性
延遲存儲(chǔ)屬性是指當(dāng)?shù)谝淮伪徽{(diào)用的時(shí)候才會(huì)計(jì)算其初始值的屬性填硕。在屬性聲明前使用lazy來(lái)表示一個(gè)延遲存儲(chǔ)屬性。
note:必須將延遲存儲(chǔ)屬性聲明成變量(使用var關(guān)鍵字),因?yàn)閷傩缘某跏贾悼赡茉趯?shí)例構(gòu)造完成之后才會(huì)得到扁眯。而常量屬性在構(gòu)造過(guò)程完成之前必須要有初始值壮莹,因此無(wú)法聲明成延遲屬性。
/* DataImporter是一個(gè)將外部文件中的數(shù)據(jù)導(dǎo)入類(lèi)姻檀,這個(gè)類(lèi)的初始化會(huì)消耗不少時(shí)間*/
class DataImporter {
var filename = "data.txt"
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
}
let manager = DataManager()
manager.data.append("some data")
manager.data.append("some more data")
//第一次訪問(wèn)時(shí)命满,才進(jìn)行初始化
print(manager.importer.filename)
note:如果一個(gè)被標(biāo)記為lazy的屬性在沒(méi)有初始化時(shí)就同時(shí)被多個(gè)線程訪問(wèn),則無(wú)法保證該屬性只會(huì)被初始化一次绣版。
5.存儲(chǔ)屬性和實(shí)例變量
Swift中的屬性沒(méi)有對(duì)應(yīng)的實(shí)例變量胶台,屬性的后端存儲(chǔ)也無(wú)法直接訪問(wèn)。這就避免了不同場(chǎng)景下訪問(wèn)方式的困擾杂抽,同時(shí)也將屬性的定義簡(jiǎn)化成一個(gè)語(yǔ)句诈唬。這個(gè)類(lèi)型中屬性的全部信息---包括命名、類(lèi)型和內(nèi)存管理特征默怨,都在唯一一個(gè)地方(類(lèi)型定義中)定義讯榕。
計(jì)算屬性
除了存儲(chǔ)屬性外,類(lèi)匙睹、構(gòu)造體和枚舉可以定義計(jì)算屬性。計(jì)算屬性不直接存儲(chǔ)值济竹,而是提供一個(gè)getter和一個(gè)可選的setter痕檬,來(lái)間接獲取和設(shè)置其他屬性或變量的值。
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center:Point {
get{
let centerX = origin.x + size.width / 2
let centerY = origin.y + size.height / 2
return Point(x: centerX, y: centerY)
}
set(newCenter){
origin.x = newCenter.x - size.width / 2
origin.y = newCenter.y - size.height / 2
}
}
}
var square = Rect(origin: Point(x:0.0,y: 0.0), size: Size(width: 10.0, height: 10.0))
let center = square.center
square.center = Point(x: 100, y: 100)
print(square)
1.便捷setter聲明
如果計(jì)算屬性的setter沒(méi)有定義表示新值的參數(shù)名送浊,則可以使用默認(rèn)newValue梦谜。下面是使用了便捷setter聲明的Rect結(jié)構(gòu)體代碼:
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center:Point {
get{
let centerX = origin.x + size.width / 2
let centerY = origin.y + size.height / 2
return Point(x: centerX, y: centerY)
}
set{
origin.x = newValue.x - size.width / 2
origin.y = newValue.y - size.height / 2
}
}
}
var square = Rect(origin: Point(x:0.0,y: 0.0), size: Size(width: 10.0, height: 10.0))
let center = square.center
square.center = Point(x: 100, y: 100)
print(square)
2.只讀計(jì)算屬性
只有g(shù)etter沒(méi)有setter的計(jì)算屬性就是只讀計(jì)算屬性。只讀計(jì)算屬性總是返回一個(gè)值袭景,可以通過(guò)點(diǎn)運(yùn)算符訪問(wèn)唁桩,但不能設(shè)置新的值。
note:必須使用var關(guān)鍵字定義屬性耸棒,包括只讀計(jì)算屬性荒澡,因?yàn)樗鼈兊闹挡皇枪潭ǖ摹et關(guān)鍵字只用來(lái)聲明常量屬性与殃,表示初始化后在也無(wú)法修改的值单山。
只讀計(jì)算屬性的聲明可以去掉get關(guān)鍵字和花括號(hào)
struct rect {
var width = 0
var height = 0
var boundLength : Int {
return (width + height) * 2;
}
}
屬性觀察器
屬性觀察器監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時(shí)候都會(huì)調(diào)用屬性觀察器幅疼,甚至新的值和現(xiàn)狀的值相同的時(shí)候也不例外米奸。
可以為除了延遲存儲(chǔ)屬性之外的其他存儲(chǔ)屬性添加屬性觀察器,也可以通過(guò)重寫(xiě)屬性的方式為繼承的屬性(包括存儲(chǔ)屬性和計(jì)算屬性)添加屬性觀察器爽篷。
note:不需要為非重寫(xiě)的計(jì)算屬性添加屬性觀察器悴晰,因?yàn)橥ㄟ^(guò)它的setter直接監(jiān)控和響應(yīng)的變化。
可以為屬性添加如下的一個(gè)或全部觀察器:
1.willSet在新的值被設(shè)置之前調(diào)用逐工。
2.didSet在新的值被設(shè)置之后立即調(diào)用铡溪。
willSet觀察器會(huì)將新的屬性值作為常量參數(shù)傳入漂辐,在willSet的實(shí)現(xiàn)代碼中可以為這個(gè)參數(shù)指定一個(gè)名稱(chēng),如果不指定則參數(shù)仍然可用佃却,這時(shí)使用默認(rèn)名稱(chēng)為newValue表示者吁。
類(lèi)似地,didSet觀察器會(huì)將舊的屬性作為參數(shù)傳入饲帅,可用為該參數(shù)命名或者使用默認(rèn)參數(shù)名oldValue复凳。
note:父類(lèi)的屬性在子類(lèi)的構(gòu)造器中被賦值時(shí),它在父類(lèi)中的willSet和didSet觀察器會(huì)被調(diào)用灶泵。
class StepCounter {
var totalSteps: Int = 0 {
willSet{
print("the new value \(newValue)")
}
didSet {
print("the old Value \(oldValue)")
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
stepCounter.totalSteps = 100
note:如果在一個(gè)屬性的didSet觀察器里為它賦值育八,這個(gè)值會(huì)替換該觀察器之前設(shè)置的值。
全局變量和局部變量
計(jì)算屬性和屬性觀察器所描述的模式也可以用于全局變量和局部變量赦邻。全局變量時(shí)在函數(shù)髓棋、方法、閉包或任何類(lèi)型之外定義的變量惶洲。局部變量時(shí)在函數(shù)按声、方法或閉包內(nèi)部定義的變量。
全局或局部變量都屬于存儲(chǔ)型變量恬吕,跟存儲(chǔ)屬性類(lèi)似签则,它提供特定類(lèi)的存儲(chǔ)空間,并允許讀取和寫(xiě)入铐料。
另外渐裂,在全局或局部范圍都可以定義計(jì)算型變量和為存儲(chǔ)類(lèi)型變量定義觀察器。計(jì)算型變量跟計(jì)算屬性一樣钠惩,返回一個(gè)計(jì)算的值而不是存儲(chǔ)值柒凉,聲明格式也完全一樣。
note:全局的常量或變量都是延遲計(jì)算的篓跛,不同的地方在于膝捞,全局的常量或變量不需要標(biāo)記lazy特性。
局部范圍的常量或變量不會(huì)延遲計(jì)算
類(lèi)型屬性
實(shí)例的屬性屬于一個(gè)特定類(lèi)型實(shí)例举塔。每次類(lèi)型實(shí)例化后都擁有自己的一套屬性值绑警,實(shí)例之間的屬性相互獨(dú)立。也可以為類(lèi)型本身定義屬性央渣,不管類(lèi)型有多少個(gè)實(shí)例计盒,這些屬性都只有唯一一份。這種屬性就是類(lèi)型屬性芽丹。
類(lèi)型屬性用于定義特定類(lèi)型所有實(shí)例共享的數(shù)據(jù)北启,比如所有的實(shí)例都能有一個(gè)常量(就像c語(yǔ)言中的鏡頭常量),或者所有實(shí)例都能訪問(wèn)的一個(gè)變量(就像c語(yǔ)言中的靜態(tài)變量)
值類(lèi)型的存儲(chǔ)型類(lèi)型屬性可以是變量或常量,計(jì)算型類(lèi)型屬性跟實(shí)例的計(jì)算屬性一樣只能定義成變量屬性咕村。
note:跟實(shí)例的存儲(chǔ)屬性不同场钉,必須給存儲(chǔ)型類(lèi)型屬性指定默認(rèn)值,因?yàn)轭?lèi)型本身無(wú)法在初始化過(guò)程中使用構(gòu)造器給類(lèi)型屬性賦值懈涛。
存儲(chǔ)型類(lèi)型屬性是延遲初始化的逛万,它們只有在第一次被訪問(wèn)的時(shí)候才會(huì)被初始化。即使它們被多個(gè)線程同時(shí)訪問(wèn)批钠,系統(tǒng)也保證只會(huì)對(duì)其進(jìn)行初始化一次宇植,并且不需要對(duì)其使用lazy修飾符。
1.類(lèi)型屬性語(yǔ)法
在c或Objective-c中埋心,與某個(gè)類(lèi)型關(guān)聯(lián)的靜態(tài)常量和靜態(tài)變量指郁,是作為全局(global)靜態(tài)變量定義的。但是在Swift編程語(yǔ)言中拷呆,類(lèi)型屬性是作為類(lèi)型定義的一部分寫(xiě)在類(lèi)型最外的花括號(hào)內(nèi)闲坎,因此它的作用范圍也就是在類(lèi)型支持的范圍內(nèi)。
使用關(guān)鍵字static來(lái)定義類(lèi)型屬性茬斧。在為類(lèi)(class)定義計(jì)算型類(lèi)型屬性時(shí)腰懂,可以使用關(guān)鍵字class來(lái)支持子類(lèi)對(duì)父類(lèi)的實(shí)現(xiàn)進(jìn)行重寫(xiě)。
struct SomeStructure {
static var storedTypeProperty = "Some value"
static var computedTypeProperty : Int {
return 6
}
}
enum SomeEnum {
static var storedTypeProperty = "Some value"
static var cpmputedTypeProperty : Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some Value"
static var computedTypeProperty : Int {
return 6
}
class var overrideableComputedTypeProperty: Int {
return 100
}
}
2.獲取和設(shè)置類(lèi)型屬性的值
跟實(shí)例的屬性一樣项秉,類(lèi)型屬性的訪問(wèn)也是通過(guò)點(diǎn)運(yùn)算符來(lái)進(jìn)行悯恍。但是,類(lèi)型屬性是通過(guò)類(lèi)型本身來(lái)獲取和設(shè)置伙狐,而不是通過(guò)實(shí)例
SomeClass.storedTypeProperty = "hello"
print(SomeClass.storedTypeProperty)
方法
方法是與某些特定類(lèi)型相關(guān)聯(lián)的函數(shù)。類(lèi)瞬欧、結(jié)構(gòu)體贷屎、枚舉都可以定義實(shí)例方法:實(shí)例方法為給類(lèi)型的實(shí)例封裝了具體的任務(wù)與功能。類(lèi)艘虎、結(jié)構(gòu)體唉侄、枚舉也可以定義類(lèi)型方法;類(lèi)型方法與類(lèi)型本身相關(guān)聯(lián)野建。類(lèi)型方法與Objective-c中的類(lèi)方法(class methods)相似属划。
結(jié)構(gòu)體和枚舉能夠定義方法是Swfit與c/Objective-c的主要區(qū)別之一。在Objective-c中候生,類(lèi)是唯一能定義方法的類(lèi)型同眯。但在Swift中,你不僅能夠選擇是否要定義一個(gè)類(lèi)/結(jié)構(gòu)體/枚舉唯鸭,還能靈活的在你創(chuàng)建的類(lèi)型(類(lèi)/結(jié)構(gòu)體/枚舉)上定義方法须蜗。
實(shí)例方法
實(shí)例方法是屬于某個(gè)特定類(lèi)、結(jié)構(gòu)體或者枚舉類(lèi)型實(shí)例的方法。實(shí)例方法提供訪問(wèn)和修改實(shí)例屬性的方法或提供了實(shí)例目的相關(guān)的功能明肮,并以此來(lái)支撐實(shí)例的功能菱农。實(shí)例方法的語(yǔ)法與函數(shù)完全一致。
實(shí)例方法要寫(xiě)在它所屬的類(lèi)型的前后大括號(hào)之間柿估。實(shí)例方法能夠隱式訪問(wèn)它所屬類(lèi)型的所有其他實(shí)例方法和屬性循未。實(shí)例方法職能被它所屬的類(lèi)的某個(gè)特定的實(shí)例調(diào)用。實(shí)例方法不能脫離于現(xiàn)實(shí)的實(shí)例而被調(diào)用秫舌。
class Counter {
var count = 0
func increment(){
count += 1;
}
func incrementBy(amount: Int){
count += amount
}
func reset(){
count = 0
}
}
方法局部參數(shù)名和外部參數(shù)名稱(chēng)
函數(shù)參數(shù)可以同時(shí)有一個(gè)局部名稱(chēng)(在函數(shù)體內(nèi)部使用)和一個(gè)外部名稱(chēng)(在調(diào)用函數(shù)時(shí)使用)的妖。方法參數(shù)也一樣(因?yàn)榉椒ň褪呛瘮?shù),只是這個(gè)函數(shù)與某個(gè)類(lèi)型相關(guān)聯(lián)了)舅巷。
Swift中的方法和Objective-c中的方法極其相似羔味。像在Objective-c中一樣,Swift中方法名稱(chēng)通常用一個(gè)介詞指向方法的第一個(gè)參數(shù)钠右,比如:with赋元,for,by等等飒房。前面的Counter類(lèi)的例子中incrementBy(_:)方法就是這樣的搁凸。介詞的使用讓方法在被調(diào)用時(shí)候能像一個(gè)句子一樣被解讀。
具體來(lái)說(shuō)狠毯,Swift默認(rèn)僅給方法的第一個(gè)參數(shù)名稱(chēng)一個(gè)局部參數(shù)名稱(chēng)护糖;默認(rèn)同時(shí)給第二個(gè)和后續(xù)的參數(shù)名稱(chēng)局部參數(shù)和外部參數(shù)名稱(chēng)。這個(gè)約定與典型的命名和調(diào)用約定相適應(yīng)嚼松,與你在寫(xiě)objective-c的方法時(shí)很相似嫡良。這個(gè)約定還讓表達(dá)式方法在調(diào)用時(shí)不需要在限定參數(shù)名稱(chēng)。
class Counter {
var count = 0
func incrementBy(amount: Int ,numberOfTimes:Int ){
count += amount * numberOfTimes
}
}
let counter = Counter()
counter.incrementBy(5, numberOfTimes: 10)
print(counter.count)
修改方法的外部參數(shù)名稱(chēng)
有時(shí)為方法的第一個(gè)參數(shù)提供一個(gè)外部參數(shù)名稱(chēng)是非常有用的献酗,盡管這不是默認(rèn)的行為寝受。我們可以自己添加一個(gè)顯式的外部名稱(chēng)作為第一個(gè)參數(shù)的前綴來(lái)把這個(gè)局部名稱(chēng)當(dāng)作外部名稱(chēng)使用。
相反罕偎,如果我們不想為方法的第二個(gè)以及后續(xù)的參數(shù)提供一個(gè)外部名稱(chēng)很澄,可以通過(guò)使用下劃線(_)作為該參數(shù)的顯式外部名稱(chēng),這樣做將覆蓋默認(rèn)行為颜及。
self屬性
類(lèi)型的每一個(gè)實(shí)例都有一個(gè)隱含屬性叫做self甩苛,self完全等同于該實(shí)例本身。我們可以在一個(gè)實(shí)例的實(shí)例方法中使用這個(gè)隱含的self屬性來(lái)引用當(dāng)前實(shí)例俏站。
func increment(){
self.count++
}
實(shí)際上讯蒲,我們不必在我們的代碼里面經(jīng)常寫(xiě)self。不論何時(shí)乾翔,只要在一個(gè)方法中使用一個(gè)已知的屬性或者方法名稱(chēng)爱葵,如果沒(méi)有明確的寫(xiě)self施戴,Swift假定你是指當(dāng)前實(shí)例的屬性或者方法。
使用這條規(guī)則的主要場(chǎng)景是實(shí)例方法的某個(gè)參數(shù)名稱(chēng)與實(shí)例方法的某個(gè)屬性名稱(chēng)相同的時(shí)候萌丈。在這種情況下赞哗,參數(shù)名稱(chēng)享有優(yōu)先權(quán),而且在引用屬性時(shí)必須使用一種更嚴(yán)格的方式辆雾。這時(shí)我們可以使用self屬性來(lái)區(qū)分參數(shù)名稱(chēng)和屬性名稱(chēng)肪笋。
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOfX(x:Double)->Bool {
return self.x > x
}
}
在實(shí)例方法中修改值類(lèi)型
結(jié)構(gòu)體和枚舉是值類(lèi)型。一般情況下度迂,值類(lèi)型的屬性不能在它的實(shí)例方法中被修改藤乙。
但是,如果你確定需要在某個(gè)具體的方法中修改結(jié)構(gòu)體或者枚舉的屬性惭墓,我們可以選擇 變異(mutating)這個(gè)方法(可變方法)坛梁,然后方法就可以從方法內(nèi)部改變它的屬性;并且它做的任何改變?cè)诜椒ńY(jié)束時(shí)會(huì)保留在原始結(jié)構(gòu)中腊凶。方法還可以給它隱含的self屬性賦值一個(gè)全新的實(shí)例划咐,這個(gè)新實(shí)例在方法結(jié)束后將替換原來(lái)的實(shí)例。
struct Point {
var x = 0.0 , y = 0.0
mutating func moveByX(x:Double , y: Double){
self.x += x
self.y += y
}
}
var somePoint = Point(x: 1, y: 1)
print("(\(somePoint.x),\(somePoint.y))")
somePoint.moveByX(100, y: 20)
print("(\(somePoint.x),\(somePoint.y))")
在可變方法中給self賦值
可變方法能夠賦給隱含屬性self一個(gè)全新的實(shí)例钧萍。
struct Point {
var x = 0.0 , y = 0.0
mutating func moveByX(x:Double , y: Double){
self = Point(x: self.x + x, y: self.y + y)
}
}
枚舉的可變方法可以把self設(shè)置為相同的枚舉類(lèi)型中不同的成員:
enum SwitchState {
case Off,Low,High
mutating func nex() {
switch self {
case Off:
self = Low
case Low:
self = High
case High:
self = Off
}
}
}
var lowState = SwitchState.Low
print(lowState)
lowState.nex()
print(lowState)
lowState.nex()
print(lowState)
lowState.nex()
print(lowState)
類(lèi)方法
實(shí)例方法是被類(lèi)型的某個(gè)實(shí)例調(diào)用的方法褐缠。你也可以定義類(lèi)型本身調(diào)用的方法,這種方法就叫做類(lèi)型方法风瘦。聲明結(jié)構(gòu)體和枚舉的類(lèi)型方法队魏,在方法的func關(guān)鍵字之前加上關(guān)鍵字static。類(lèi)可以使用關(guān)鍵在class來(lái)允許子類(lèi)重寫(xiě)父類(lèi)的實(shí)現(xiàn)方法万搔。
note:在objective-c里面胡桨,我們只能為類(lèi)定義類(lèi)型方法。在Swift中瞬雹,我們可以為所有的類(lèi)登失、結(jié)構(gòu)體和枚舉定義類(lèi)型方法;每一個(gè)類(lèi)型方法都被它所支持的類(lèi)型顯式包含挖炬。
類(lèi)型方法和實(shí)例方法一樣用點(diǎn)語(yǔ)法調(diào)用。但是状婶,我們?cè)陬?lèi)型層面上調(diào)用這個(gè)方法意敛,而不是在實(shí)例層面上調(diào)用。
在類(lèi)型方法的方法體中膛虫,self指向這個(gè)類(lèi)型本身草姻,而不是類(lèi)型的某個(gè)實(shí)例。對(duì)于結(jié)構(gòu)體和枚舉來(lái)說(shuō)稍刀,這意味著我們可以用self來(lái)消除靜態(tài)屬性和靜態(tài)方法參數(shù)之間的歧義撩独。
一般來(lái)說(shuō)敞曹,任何未限定的方法和屬性名稱(chēng),將會(huì)來(lái)自于本類(lèi)中另外的類(lèi)型級(jí)別的方法和屬性综膀。一個(gè)類(lèi)型方法可以調(diào)用本類(lèi)中另一個(gè)類(lèi)型方法的名稱(chēng)澳迫,而無(wú)需在方法名稱(chēng)前面加上類(lèi)型名稱(chēng)的前綴。同樣剧劝,結(jié)構(gòu)體和枚舉的類(lèi)型方法也能過(guò)直接通過(guò)靜態(tài)屬性的名稱(chēng)訪問(wèn)靜態(tài)屬性橄登,而不需要類(lèi)型名稱(chēng)前綴。