在此處輸入標題
標簽(空格分隔): 未分類
1.類和結構體
? swift支持直接設置結構體中的子屬性
? 所有結構體都有一個自動生成的成員逐一構造器方法贞让,類沒有
? swift中,所有的結構體和枚舉類型都是值類型爽航,那么意味著在代碼中傳遞時葵袭,都會被復制曲秉。和基本類型類似齐苛,都是值類型
? 類是引用類型,可以使用恒等運算符 等價于 === 或者不等價于 朦蕴!== 檢測兩個常量或者變量是否引用同一個實例。
總結:結構體實例總是通過值傳遞弟头,類實例總是通過引用傳遞
按照通用的準則吩抓,當符合一條或多條以下條件時,請考慮構建結構體:
? 該數(shù)據(jù)結構的主要目的是用來封裝少量相關簡單數(shù)據(jù)值赴恨。
? 有理由預計該數(shù)據(jù)結構的實例在被賦值或傳遞時疹娶,封裝的數(shù)據(jù)將會被拷貝而不是被引用。 ? 該數(shù)據(jù)結構中儲存的值類型屬性伦连,也應該被拷貝雨饺,而不是被引用。
? 該數(shù)據(jù)結構不需要去繼承另一個既有類型的屬性或者行為除师。
2.字符串沛膳、數(shù)組、和字典類型的賦值與復制行為:
Swift 中汛聚,許多基本類型锹安,諸如 String , Array 和 Dictionary 類型均以結構體的形式實現(xiàn)倚舀。這意味著被賦值給 新的常量或變量叹哭,或者被傳入函數(shù)或方法中時,它們的值會被拷貝痕貌。
Objective-C 中 NSString 风罩, NSArray 和 NSDictionary 類型均以類的形式實現(xiàn),而并非結構體舵稠。它們在被賦值或 者被傳入函數(shù)或方法時超升,不會發(fā)生值拷貝,而是傳遞現(xiàn)有實例的引用
以上是對字符串哺徊、數(shù)組室琢、字典的“拷貝”行為的描述。在你的代碼中落追,拷貝行為看起來似乎總會發(fā)生盈滴。然而,Sw ift 在幕后只在絕對必要時才執(zhí)行實際的拷貝轿钠。Swift 管理所有的值拷貝以確保性能最優(yōu)化巢钓,所以你沒必要去回 避賦值來保證性能最優(yōu)化
3.屬性
如果創(chuàng)建了一個結構體的實例并將其賦值給一個常量病苗,則無法修改該實例的任何屬性,即使有屬性被聲明為變量也不行:這種行為是由于結構體(struct)屬于值類型症汹。當值類型的實例被聲明為常量的時候硫朦,它的所有屬性也就成了常 量。
延遲存儲屬性是指當?shù)谝淮伪徽{(diào)用的時候才會計算其初始值的屬性烈菌。在屬性聲明前使用 lazy 來標示一個延遲存 儲屬性阵幸。使用 var 關鍵字。
除存儲屬性外芽世,類、結構體和枚舉可以定義計算屬性诡壁。計算屬性 不直接存儲值济瓢,而是提供一個 getter 和一個可 選的 setter,來間接獲取和設置其他屬性或變量的值妹卿。必須使用 關鍵字定義計算屬性;只讀計算屬性的聲明可以去掉 關鍵字和花括號
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)
}
} }
可以為除了延遲存儲屬性之外的其他存儲屬性添加 屬性觀察器
? willSet 在新的值被設置之前調(diào)用
? didSet 在新的值被設置之后立即調(diào)用
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
} }
} }
全局的常量或變量都是延遲計算的旺矾,跟延遲存儲屬性 (頁 0)相似,不同的地方在于夺克,全局的常量或變量不需要 標記 lazy 修飾符箕宙。
類型屬性用于定義某個類型所有實例共享的數(shù)據(jù),比如所有實例都能用的一個常量(就像 C 語言中的靜態(tài)常 量)铺纽,或者所有實例都能訪問的一個變量(就像 C 語言中的靜態(tài)變量)柬帕。
使用關鍵字 static 來定義類型屬性
跟實例的存儲型屬性不同,必須給存儲型類型屬性指定默認值狡门,因為類型本身沒有構造器陷寝,也就無法在初始化過 程中使用構造器給類型屬性賦值。 存儲型類型屬性是延遲初始化的其馏,它們只有在第一次被訪問的時候才會被初始化凤跑。即使它們被多個線程同時訪 問,系統(tǒng)也保證只會對其進行一次初始化叛复,并且不需要對其使用 lazy 修飾符仔引。
方法
結構體和枚舉能夠定義方法是 Swift 與 C/Objective-C 的主要區(qū)別之一。在 Objective-C 中褐奥,類是唯一能定義 方法的類型
參數(shù)名稱與實例的某個屬性名稱相同的時候咖耘,參數(shù)名 稱享有優(yōu)先權,可以使用 self 屬性來區(qū)分參數(shù)名稱和屬性 名稱
在實例方法中修改值類型:
結構體和枚舉是值類型抖僵。默認情況下鲤看,值類型的屬性不能在它的實例方法中被修改,如果你確實需要在某個特定的方法中修改結構體或者枚舉的屬性耍群,可以定義可變方法: 在方法前加關鍵字mutating义桂,然后就可以從其方法內(nèi)部改變它的屬性找筝。
注意,不能在結構體類型的常量(a constant of structure type)上調(diào)用可變方法慷吊,因為其屬性不能被改 變袖裕,即使屬性是變量屬性
類方法:在方法的 func 關鍵字之前加上關鍵字 static ,來指定類型方法溉瓶。類還可以用關鍵字 class 來允許子類重寫 父類的方法實現(xiàn)急鳄。
下標:下標可以定義在類、結構體和枚舉中堰酿,是訪問集合疾宏,列表或序列中元素的快捷方式。定義下標使用 subscript 關鍵字触创,多下標參數(shù)用逗號分隔
subscript(index: Int) -> Int {
get {
// 返回一個適當?shù)?Int 類型的值 }
set(newValue) {
// 執(zhí)行適當?shù)馁x值操作
} }
//可以不指定set的參數(shù)坎藐,會有默認參數(shù):newValue;
如果只提供get 方法哼绑,那么可以省去get 關鍵字
其實下標語法其實是有對應的方法支撐的岩馍。和數(shù)組的下標用法一樣。比常規(guī)數(shù)組的下標強大抖韩,類似重寫蛀恩。數(shù)組和字典在swift中已經(jīng)默認實現(xiàn)了下標語法,所以我們可以直接使用茂浮。
繼承:
在重寫繼承來的方法時双谆,需要用 override 聲明。該關鍵字聲明保證編譯器去檢查超類或父類励稳,否則編譯會報錯佃乘,因為方法名重復了。
重寫屬性: 你可以重寫繼承來的實例屬性或類型屬性驹尼,提供自己定制的 getter 和 setter趣避,或添加屬性觀察器使重寫的屬性,可以觀察屬性值什么時候發(fā)生改變;你可以將一個繼承來的只讀屬性重寫為一個讀寫屬性,只需要在重寫版本的屬性里提供 getter 和 setter 即 可新翎。但是程帕,你不可以將一個繼承來的讀寫屬性重寫為一個只讀屬性,如果你在重寫屬性中提供了 setter,那么你也一定要提供 getter
此外還要注意地啰,你不可以同時提供重寫的 setter 和重寫的屬性觀察器愁拭。如果你想觀察屬性值的變化,并且你已 經(jīng)為那個屬性提供了定制的 setter亏吝,那么你在 setter 中就可以觀察到任何值變化了岭埠。
防止重寫
你可以通過把方法,屬性或下標標記為 來防止它們被重寫,只需要在聲明關鍵字前加上final修飾符即 可(例如:final var 惜论,final func,final class func, final subscript )许赃。
你可以通過在關鍵字 class前添加 final修飾符來將整個類標記為 final 的。這樣的類是不可被繼承的馆类,試圖繼承這樣的類會導致編譯報錯
構造過程:
存儲屬性的初始賦值:類和結構體在創(chuàng)建實例時混聊,必須為所有存儲型屬性設置合適的初始值。存儲型屬性的值不能處于一個未知的狀態(tài)乾巧。你可以在構造器中為存儲型屬性賦初值句喜,也可以在定義屬性時為其設置默認值;
參數(shù)的內(nèi)部名稱和外部名稱
構造過程中常量屬性的修改沟于。對于類的實例來說咳胃,它的常量屬性只能在定義它的類的構造過程中修改;不能在子類中修改
結構體的逐一成員構造器:如果結構體沒有提供自定義的構造器,它們將自動獲得一個逐一成員構造器
假如你希望默認構造器旷太、逐一成員構造器以及你自己的自定義構造器都能用來創(chuàng)建實例拙绊,可以將自定義的構造器寫到擴展(extension)中,而不是寫在值類型的原始定義中泳秀。
值類型的構造器代理:構造器可以通過調(diào)用其它構造器來完成實例的部分構造過程。這一過程稱為構造器代理榄攀,它能減少多個構造器間
的代碼重復.`
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)// 這里使用的就是構造器代理的方式
} }
類的繼承和構造過程
類里面的所有存儲型屬性——包括所有繼承自父類的屬性——都必須在構造過程中設置初始值嗜傅。指定構造器和便利 構造器
每一個類都必須擁有至少一個指定構造器;便利構造器是類中比較次要的檩赢、輔助型的構造器:快捷調(diào)用某個指定構造器吕嘀,能夠節(jié)省更多開發(fā)時間并讓類的構造過程更清晰明了,便利構造器需要使用:convenience關鍵字修飾
init(parameters) {
statements
}
便利構造器:
convenience init(parameters) {
statements
}
類的構造器代理規(guī)則:指定構造器必須總是向上代理贞瞒;便利構造器必須總是橫向代理偶房,便利構造器需要最終調(diào)用一個指定構造器。
構造器的繼承和重寫
跟 Objective-C 中的子類不同军浆,Swift中的子類默認情況下不會繼承父類的構造器棕洋。Swift 的這種機制可以防止一個父類的簡單構造器被一個更精細的子類繼承,并被錯誤地用來創(chuàng)建子類的實例乒融。注意父類的構造器僅會在安全和適當?shù)那闆r下被繼承掰盘,你在子類中“重寫”一個父類便利構造器時,不需要加override前綴赞季。子類可以在初始化時修改繼承來的變量屬性愧捕,但是不能修改繼承來的常量屬性
子類在默認情況下不會繼承父類的構造器。但是如果滿足特定條件申钩,父類構造器是可以被自動繼承
的規(guī)則 1 如果子類沒有定義任何指定構造器次绘,它將自動繼承所有父類的指定構造器。
規(guī)則 2 如果子類提供了所有父類指定構造器的實現(xiàn)——無論是通過規(guī)則 1繼承過來的,還是提供了自定義實現(xiàn)——它將自動繼承所有父類的便利構造器邮偎。
可失敗構造器
其語法為在 init 關鍵字后面添加問號( init? )管跺。
你通過 return nil 語句來表明可失敗構造器在何種 情況下應該“失敗”。
嚴格來說钢猛,構造器都不支持返回值伙菜。因為構造器本身的作用,只是為了確保對象能被正確構造命迈。因此你只是用 return nil 表明可失敗構造器構造失敗贩绕,而不要用關鍵字 return 來表明構造成功。
帶原始值的枚舉類型會自帶一個可失敗構造器 init?(rawValue:) 壶愤,該可失敗構造器有一個名為 rawValue 的參 數(shù)淑倾,其類型和枚舉類型的原始值類型一致,如果該參數(shù)的值能夠和某個枚舉成員的原始值匹配征椒,則該構造器會構 造相應的枚舉成員娇哆,否則構造失敗。
構造失敗的傳遞,可以橫向代理到類型中的其他可失敗構造器勃救,類似的子類也可以代理到父類中的可失敗構造器碍讨;重寫一個可失敗構造器:
如同其它的構造器,你可以在子類中重寫父類的可失敗構造器蒙秒〔颍或者你也可以用子類的非可失敗構造器重寫一個父類的可失敗構造器<強制對父類值解包>。這使你可以定義一個不會構造失敗的子類晕讲,即使父類的構造器允許構造失敗,你可以用非可失敗構造器重寫可失敗構造器覆获,但反過來卻不行另外的一種可失敗構造的方式是用驚嘆號!代替問號瓢省?: (init!)
該可失敗構造器將會構建一個對應類型的隱式解 包可選類型的對象弄息;
你可以在 init? 中代理到 init! ,反之亦然勤婚。你也可以用 init? 重寫 init! 摹量,反之亦然。你還可以用 init 代理 到 init! 蛔六,不過荆永,一旦 init! 構造失敗,則會觸發(fā)一個斷言国章。
必要構造器
- 在類的構造器前添加 required 修飾符表明所有該類的子類都必須實現(xiàn)該構造器:
class SomeClass {
required init() {
// 構造器的實現(xiàn)代碼
}
}
在子類重寫父類的 必要構造器 時具钥,必須在子類的構造器前也添加 required 修飾符,表明該構造器要求也應用于繼承鏈后面的子類液兽。在重寫父類中必要的指定構造器時骂删,不需要添加 override 修飾符:
class SomeSubclass: SomeClass {
required init() {
// 構造器的實現(xiàn)代碼 }
}
如果子類繼承的構造器能滿足必要構造器的要求掌动,則無須在子類中顯式提供必要構造器的實現(xiàn)∧担《待理解》