Method
-
方法
與計算型屬性
的使用選取
1.優(yōu)先考慮使用 computed property
(計算型屬性) 戏阅,可以利用setter 昼弟、getter方法。
2.如果不需要用到setter
/getter
奕筐,并且需要處理數(shù)據(jù)庫相關(guān)的復(fù)雜任務(wù)舱痘,那么建議使用方法Method
.
struct person {
var name: String
//很顯然可以使用計算型屬性來代替
func age() -> Int {
return 20
}
}
Tip: 一個返回單一值的方法,顯然沒有什么必要存在离赫。
- self 介紹
一個結(jié)構(gòu)體定義更像是一張藍圖芭逝,它的實例 Instance
作為一個真實的對象存在。Swift 編譯器默認將self
作為一個隱含參數(shù)渊胸,傳遞給了method
旬盯。在結(jié)構(gòu)體內(nèi)部,允許使用 self
訪問實例的屬性或方法翎猛。
struct person {
var name: String
var age: Int
//這種傳參方式?jīng)]有什么意義
func description(name: String, age: Int) -> String {
return "\(name)'s age is \(age)"
}
}
Tip:換句話說胖翰,一個實例的方法如果訪問的都是自身的屬性,那么將他們作為參數(shù)傳遞以增加函數(shù)的復(fù)雜度是沒有任何意義的切厘。
構(gòu)造函數(shù)
之前提到萨咳,Swift會根據(jù)結(jié)構(gòu)體類型的屬性來自動創(chuàng)建構(gòu)造函數(shù)(包含所有屬性,強制初始化)疫稿,這僅僅是為了保證生成實例時保證所有屬性是可以使用的狀態(tài)培他。
struct Test{
var name: String
var age: Int
/*
//這個也被稱為 簡單構(gòu)造函數(shù)
init() {
name = "Tom"
age = 18
}
*/
///自定義構(gòu)造函數(shù)
func init(name: String, age: Int){
//這里需要注意
/*
//wrong 不要試圖,因為編譯器并不會知道哪個才是本地屬性
name = name
age = age
*/
self.name = name
self.age = age
}
func description() -> String {
return name + String(age)
}
}
///注意而克,如果上面的構(gòu)造函數(shù)處于注釋狀態(tài)靶壮,
///那么系統(tǒng)就會強制我們使用系統(tǒng)自動創(chuàng)建的構(gòu)造函數(shù)來進行實例生成。
let test = Test(name: <String>, age: <Int>)
///打開注釋员萍,才可以使用已經(jīng)定義好的 init()構(gòu)造函數(shù)腾降,而自動生成的構(gòu)造函數(shù)會變的不可用。
let testA = Test()
Tip:在你決定創(chuàng)建構(gòu)造函數(shù)時碎绎,也就意味著放棄了使用系統(tǒng)為你自動創(chuàng)建好的構(gòu)造函數(shù)螃壤。
- mutating methods (修改實例屬性會遇到系統(tǒng)的保護屏障)
struct Test{
var name: String
var age: Int
init() {
name = "Tom"
age = 18
}
func description() -> String {
return name + String(age)
}
///修改age 的方法
func changeAge() {
age += 2
}
}
可以看到抗果,我們創(chuàng)建了一個方法用來修改屬性age〖榍纾可以一旦編譯冤馏,編譯器會報如下錯誤:
Left side of mutating operator isn't mutable: 'self' is immutable
該錯誤的含義,仿佛是系統(tǒng)在告訴我們self
及其屬性在結(jié)構(gòu)體中默認是不可變的寄啼。當(dāng)然逮光,這是不包括構(gòu)造函數(shù)的。顯然墩划,設(shè)計者并不希望我們隨意改變內(nèi)部環(huán)境涕刚。
- 思考一: 結(jié)構(gòu)體作為系統(tǒng)提供的最基本數(shù)據(jù)類型,在某種程度上其類似于
OC
中NSObject
的地位乙帮。 - 思考二: 足夠微小的基本類型杜漠,應(yīng)該默認是固化的狀態(tài)。
- 思考三: 內(nèi)部不應(yīng)該含有不直觀的察净、隱藏的狀態(tài)變更
- 思考四: 結(jié)構(gòu)體是值類型valueType驾茴,copy-on-write
///遵照系統(tǒng)提示,我們會很容易注意到關(guān)鍵字 mutating operator 氢卡,修改如下
mutating func changeAge(){
age += 2
}
//由于結(jié)構(gòu)體是值類型锈至,當(dāng)期作為參數(shù)傳遞時或者賦值時,默認會發(fā)生拷貝操作译秦。那么如果內(nèi)部存在能夠影響屬性值的方法裹赴,很有可能會導(dǎo)致原結(jié)構(gòu)體和拷貝后的結(jié)構(gòu)體會不一致。
mutating
操作中诀浪,Swift會隱含完成以下步驟:
1.被標記為'mutating'的函數(shù),默認調(diào)用者將不再是固化的延都,也就是常量雷猪,應(yīng)該是一個變量。
2.Swift會悄悄的把傳入的隱含參數(shù)'self',標記為'inout'. 概念上類似于晰房,傳址求摇。
- 類型方法(Type methods)
和類型屬性(Type properties)一樣,我們也可以自定義類型方法殊者,在類型方法中我們可以訪問全部的類型屬性与境。其實這也是另一種單例形式~ 關(guān)鍵字static
Struct Person {
static func typeFunc(){
print("do whatever you want...")
}
}
//調(diào)用
Person.typeFunc()
- 為結(jié)構(gòu)體添加擴展(僅限方法、構(gòu)造函數(shù)猖吴、計算型屬性)
同OC中類別Category
的概念一樣摔刁,Swift中我們也可以很方便的通過擴展extension
為類型添加方法,計算型屬性等海蔽。
extension Person {
static func typeFuncA() {
print("添加類型方法")
}
static var typeComputeProperty:String {
return "類型計算型屬性"
}
func instanceFuncA() {
print("添加實例方法")
}
var instanceProperty:String {
return "實例計算型屬性"
}
init() {
print("添加了構(gòu)造函數(shù)")
}
}
上面的是會成功的情況共屈,那么我們做一些錯誤嘗試绑谣,來看一下編譯器的反應(yīng)。
///保留上面的擴展拗引,新建一個擴展
extension Person {
/**
再次添加一個構(gòu)造函數(shù)
*/
init() {
}
//編譯器報錯 Invalid redeclaration of 'init()'
/**
添加一個已有的方法
*/
func instanceFuncA() {
print("添加實例方法")
}
//編譯器報錯 note: 'emptyFunc()' previously declared
//那么 復(fù)寫呢
override func instanceFuncA() {
print("添加實例方法")
}
//結(jié)果還是一樣的警告借宵,感興趣的可以試一下復(fù)寫屬性等等
}
能夠基本得出的結(jié)論,Swift 分類中是不能復(fù)寫類型中已有的函數(shù)矾削、屬性的壤玫。這種限制也很合理,畢竟是不安全的行為哼凯。
還有一個有趣的現(xiàn)象欲间,上面已經(jīng)講過當(dāng)你為類型實現(xiàn)了構(gòu)造函數(shù)時,就默認放棄了系統(tǒng)自動生成的構(gòu)造函數(shù)的權(quán)利挡逼。不過括改,通過類別,我們可以做到讓自定義的構(gòu)造函數(shù)和自動構(gòu)造函數(shù)同時可用家坎。
struct Test{
var varA:String
var varB:String
}
//可用
Test(varA: "A",varB: "B")
extension Test{
init(){
varA = "A"
varB = "B"
}
}
//同時可用
Test()
Test(varA: "A",varB: "B")
在這里給自己留一個問題嘱能,為什么
Swift
不可以添加存儲型屬性?