實(shí)例方法
實(shí)例方法是屬于某個(gè)特定類捧灰、結(jié)構(gòu)體或者枚舉類型實(shí)例的方法。實(shí)例方法提供訪問和修改實(shí)例屬性的方法或提供與實(shí)例目的相關(guān)的功能统锤,并以此來支撐實(shí)例的功能毛俏。
實(shí)例方法要寫在它所屬的類型的前后大括號(hào)之間。實(shí)例方法能夠隱式訪問它所屬類型的所有的其他實(shí)例方法和屬性饲窿。實(shí)例方法只能被它所屬的類的某個(gè)特定實(shí)例調(diào)用煌寇。實(shí)例方法不能脫離于現(xiàn)存的實(shí)例而被調(diào)用。
self 屬性(The self Property)
類型的每一個(gè)實(shí)例都有一個(gè)隱含屬性叫做self
逾雄,self
完全等同于該實(shí)例本身阀溶。你可以在一個(gè)實(shí)例的實(shí)例方法中使用這個(gè)隱含的self
屬性來引用當(dāng)前實(shí)例。
class Person {
var name: String?
func setName(name: String) {
self.name = name
}
}
let person = Person()
person.setName(name: "Tom")
person.name // Tom
在實(shí)例方法中修改值類型(Modifying Value Types from Within Instance Methods)
結(jié)構(gòu)體和枚舉是值類型鸦泳。默認(rèn)情況下银锻,值類型的屬性不能在它的實(shí)例方法中被修改。
但是做鹰,如果你確實(shí)需要在某個(gè)特定的方法中修改結(jié)構(gòu)體或者枚舉的屬性击纬,你可以為這個(gè)方法選擇可變(mutating)
行為,然后就可以從其方法內(nèi)部改變它的屬性钾麸;并且這個(gè)方法做的任何改變都會(huì)在方法執(zhí)行結(jié)束時(shí)寫回到原始結(jié)構(gòu)中更振。方法還可以給它隱含的self
屬性賦予一個(gè)全新的實(shí)例炕桨,這個(gè)新實(shí)例在方法結(jié)束時(shí)會(huì)替換現(xiàn)存實(shí)例。
要使用可變
方法殃饿,將關(guān)鍵字mutating
放到方法的func
關(guān)鍵字之前就可以了:
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)"
上面的Point
結(jié)構(gòu)體定義了一個(gè)可變方法 moveByX(_:y:)
來移動(dòng)Point
實(shí)例到給定的位置谋作。該方法被調(diào)用時(shí)修改了這個(gè)點(diǎn)芋肠,而不是返回一個(gè)新的點(diǎn)乎芳。方法定義時(shí)加上了mutating
關(guān)鍵字,從而允許修改屬性帖池。
注意奈惑,不能在結(jié)構(gòu)體類型的常量(a constant of structure type)上調(diào)用可變方法,因?yàn)槠鋵傩圆荒鼙桓淖兯冢词箤傩允亲兞繉傩浴?/p>
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveByX(2.0, y: 3.0)
// 這里將會(huì)報(bào)告一個(gè)錯(cuò)誤
在可變方法中給 self 賦值(Assigning to self Within a Mutating Method)
可變方法能夠賦給隱含屬性self
一個(gè)全新的實(shí)例肴甸。上面Point
的例子可以用下面的方式改寫:
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
新版的可變方法moveByX(_:y:)
創(chuàng)建了一個(gè)新的結(jié)構(gòu)體實(shí)例,它的 x 和 y 的值都被設(shè)定為目標(biāo)值囚巴。調(diào)用這個(gè)版本的方法和調(diào)用上個(gè)版本的最終結(jié)果是一樣的原在。
枚舉的可變方法可以把self
設(shè)置為同一枚舉類型中不同的成員:
enum TriStateSwitch {
case Off, Low, High
mutating func next() {
switch self {
case .Off:
self = .Low
case .Low:
self = .High
case .High:
self = .Off
}
}
}
var ovenLight = TriStateSwitch.Low
ovenLight.next()
// ovenLight 現(xiàn)在等于 .High
ovenLight.next()
// ovenLight 現(xiàn)在等于 .Off
上面的例子中定義了一個(gè)三態(tài)開關(guān)的枚舉。每次調(diào)用next()
方法時(shí)彤叉,開關(guān)在不同的電源狀態(tài)(Off
庶柿,Low
,High
)之間循環(huán)切換秽浇。
類型方法 (Type Methods)
實(shí)例方法是被某個(gè)類型的實(shí)例調(diào)用的方法浮庐。你也可以定義在類型本身上調(diào)用的方法,這種方法就叫做類型方法(Type Methods)柬焕。
注意
在 Swift 中审残,你可以為所有的類、結(jié)構(gòu)體和枚舉定義類型方法斑举。每一個(gè)類型方法都被它所支持的類型顯式包含搅轿。
類型方法和實(shí)例方法一樣用點(diǎn)語(yǔ)法調(diào)用。但是富玷,你是在類型上調(diào)用這個(gè)方法介时,而不是在實(shí)例上調(diào)用。下面是如何在SomeClass
類上調(diào)用類型方法的例子:
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
相當(dāng)于OC中的+
方法(類方法)
在類型方法的方法體(body)中凌彬,self
指向這個(gè)類型本身沸柔,而不是類型的某個(gè)實(shí)例。這意味著你可以用self
來消除類型屬性和類型方法參數(shù)之間的歧義(類似于我們?cè)谇懊嫣幚韺?shí)例屬性和實(shí)例方法參數(shù)時(shí)做的那樣)铲敛。
下標(biāo)
下標(biāo)允許你通過在實(shí)例名稱后面的方括號(hào)中傳入一個(gè)或者多個(gè)索引值來對(duì)實(shí)例進(jìn)行存取褐澎。語(yǔ)法類似于實(shí)例方法語(yǔ)法和計(jì)算型屬性語(yǔ)法的混合。與定義實(shí)例方法類似伐蒋,定義下標(biāo)使用subscript
關(guān)鍵字工三,指定一個(gè)或多個(gè)輸入?yún)?shù)和返回類型迁酸;與實(shí)例方法不同的是,下標(biāo)可以設(shè)定為讀寫或只讀俭正。這種行為由 getter 和 setter 實(shí)現(xiàn)奸鬓,有點(diǎn)類似計(jì)算型屬性:
subscript(index: Int) -> Int {
get {
// 返回一個(gè)適當(dāng)?shù)?Int 類型的值
}
set(newValue) {
// 執(zhí)行適當(dāng)?shù)馁x值操作
}
}
newValue
的類型和下標(biāo)的返回類型相同。如同計(jì)算型屬性掸读,可以不指定 setter 的參數(shù)(newValue
)串远。如果不指定參數(shù),setter 會(huì)提供一個(gè)名為newValue
的默認(rèn)參數(shù)儿惫。
如同只讀計(jì)算型屬性澡罚,可以省略只讀下標(biāo)的get
關(guān)鍵字:
subscript(index: Int) -> Int {
// 返回一個(gè)適當(dāng)?shù)?Int 類型的值
}
下面代碼演示了只讀下標(biāo)的實(shí)現(xiàn),這里定義了一個(gè)TimesTable
結(jié)構(gòu)體肾请,用來表示傳入整數(shù)的乘法表:
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
threeTimesTable[1] // 3
注意
TimesTable
例子基于一個(gè)固定的數(shù)學(xué)公式留搔,對(duì)threeTimesTable[someIndex]
進(jìn)行賦值操作并不合適,因此下標(biāo)定義為只讀的铛铁。
類型屬性語(yǔ)法
在 C 或 Objective-C 中隔显,與某個(gè)類型關(guān)聯(lián)的靜態(tài)常量和靜態(tài)變量,是作為全局(global)靜態(tài)變量定義的饵逐。但是在 Swift 中括眠,類型屬性是作為類型定義的一部分寫在類型最外層的花括號(hào)內(nèi),因此它的作用范圍也就在類型支持的范圍內(nèi)梳毙。
使用關(guān)鍵字 static
來定義類型屬性哺窄。在為類定義計(jì)算型類型屬性時(shí),可以改用關(guān)鍵字 class
來支持子類對(duì)父類的實(shí)現(xiàn)進(jìn)行重寫账锹。下面的例子演示了存儲(chǔ)型和計(jì)算型類型屬性的語(yǔ)法:
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
class A: SomeClass {
override class var overrideableComputedTypeProperty: Int {
return 10
}
}
注意
例子中的計(jì)算型類型屬性是只讀的萌业,但也可以定義可讀可寫的計(jì)算型類型屬性,跟計(jì)算型實(shí)例屬性的語(yǔ)法相同奸柬。
一個(gè)類可以繼承(inherit)另一個(gè)類的方法(methods)生年,屬性(properties)和其它特性。當(dāng)一個(gè)類繼承其它類時(shí)廓奕,繼承類叫子類(subclass)抱婉,被繼承類叫超類(或父類,superclass)桌粉。在 Swift 中蒸绩,繼承是區(qū)分「類」與其它類型的一個(gè)基本特征。
在 Swift 中铃肯,類可以調(diào)用和訪問超類的方法患亿,屬性和下標(biāo)(subscripts),并且可以重寫(override)這些方法押逼,屬性和下標(biāo)來優(yōu)化或修改它們的行為步藕。Swift 會(huì)檢查你的重寫定義在超類中是否有匹配的定義惦界,以此確保你的重寫行為是正確的。
可以為類中繼承來的屬性添加屬性觀察器(property observers)咙冗,這樣一來沾歪,當(dāng)屬性值改變時(shí),類就會(huì)被通知到雾消≡植可以為任何屬性添加屬性觀察器,無論它原本被定義為存儲(chǔ)型屬性(stored property)還是計(jì)算型屬性(computed property)仪或。