更多內容,歡迎關注公衆號:Swift花園
喜歡文章?不如來點贊關注吧?
Swift的類也能讓你建立帶有屬性和方法的新類型,這一點和結構體很類似,可是它們之間有五個顯著的區別。下面讓我一一爲你說明。編程
類和結構體的第一個區別是類沒有逐一成員構造器。這意味着只要你的類裏有屬性,你就必須自行建立構造器。swift
舉個例子:安全
class Dog { var name: String var breed: String init(name: String, breed: String) { self.name = name self.breed = breed } }複製代碼
建立類的實例跟建立結構體的實例方式同樣:markdown
let poppy = Dog(name: "Poppy", breed: "Poodle")複製代碼
類和結構體的第二個區別是類能夠繼承已經存在的類。新的類繼承了原始類全部的屬性和方法。ide
這個過程被稱爲 類繼承 或者 子類化, 被繼承的類稱爲 「父類」 或者 「超類」, 而新的類稱爲 「子類」 。spa
下面是一個 Dog
類:翻譯
class Dog { var name: String var breed: String init(name: String, breed: String) { self.name = name self.breed = breed } }複製代碼
如今讓咱們基於 Dog
來建立一個新的類 Poodle
。默認狀況下,它會繼承 Dog
的全部屬性以及構造器。code
class Poodle: Dog { }複製代碼
不過,咱們也能夠爲 Poodle
建立本身的構造器。咱們知道這個類的 breed
屬性老是 「Poodle」,所以咱們能夠建立一個只有 name
屬性的構造器。而且,咱們能夠在 Poodle
的構造器裏直接調用 Dog
的構造器,以便發生和 Dog
相同的構造過程。orm
class Poodle: Dog { init(name: String) { super.init(name: name, breed: "Poodle") } }複製代碼
出於安全性考慮,Swift會要求你老是在子類裏調用 super.init()
,以防止類在構造時來自父類的一些重要工做被遺漏。對象
子類能夠將父類的方法替換爲本身的實現,這個過程被稱爲 重寫。 讓咱們給 Dog
類添加一個 makeNoise()
方法:
class Dog { func makeNoise() { print("Woof!") } }複製代碼
若是你建立一個 Poodle
類繼承自 Dog
,它會繼承 makeNoise()
方法。 「Woof!」:
class Poodle: Dog { } let poppy = Poodle() poppy.makeNoise()複製代碼
方法重寫使得咱們能夠爲 Poodle
類從新實現 makeNoise()
。
Swift要求咱們在重寫方法時用 override func
而不是 func
,這個限定防止你在本身不知情的狀況下偶然重寫方法。另外,試圖重寫一個父類中並不存在的方法,你會遭遇錯誤。
class Poodle: Dog { override func makeNoise() { print("Yip!") } }複製代碼
經過這個修改,poppy.makeNoise()
將打印出 「Yip!」,而不是 「Woof!」。
儘管類繼承十分有用,而且蘋果的平臺在許多地方要求你大量使用它,有的時候你會但願阻止其餘開發者基於你的類構建新的類。
Swift給了咱們 final
關鍵字用於實現這種意圖:當你把一個類聲明爲final時,將沒有類可以繼承它。這意味着沒有人能經過重寫方法來改變這個類的行爲。
只須要把 final
關鍵字放在類前面,就像這樣:
final class Dog { var name: String var breed: String init(name: String, breed: String) { self.name = name self.breed = breed } }複製代碼
類和結構體的第三個區別是它們被複制的方式。當你複製一個結構體時,原始對象和複製體是不同的兩個東西,改變其中一個並不會改變另一個。當你複製一個 類 時,原始對象和複製體都指向相同的東西,因此改變其中一個也會改變另外一個。
舉個例子,有一個簡單的 Singer
類,它有一個帶有默認值的 name
屬性:
class Singer { var name = "Taylor Swift" }複製代碼
當咱們建立一個這個類的實例而且打印它的name時,咱們會獲得「Taylor Swift」:
var singer = Singer() print(singer.name)複製代碼
當咱們基於第一個實例建立第二實例而且改變第二個實例的name時:
var singerCopy = singer singerCopy.name = "Justin Bieber"複製代碼
因爲類的工做機制,singer
和 singerCopy
指向內存裏的同一個對象。因此當咱們打印 singer的name時,咱們也會獲得「Justin Bieber」:
print(singer.name)複製代碼
另外一方面,假如 Singer
是一個結構體,那第二次咱們還將獲得 「Taylor Swift」:
struct Singer { var name = "Taylor Swift" }複製代碼
類和結構體的第四個區別是類有 析構器,它是一個類的實例被銷燬時執行的代碼。
這裏有一個 Person
類,它有一個 name
屬性,一個簡單的構造器,以及一個打印信息的 printGreeting()
方法:
class Person { var name = "John Doe" init() { print("\(name) is alive!") } func printGreeting() { print("Hello, I'm \(name)") } }複製代碼
咱們將利用循環建立幾個 Person
類的實例,每次循環流轉的時候,一個新的 Person
都會被建立,以後被銷燬:
for _ in 1...3 { let person = Person() person.printGreeting() }複製代碼
來到咱們的析構器。每當 Person
實例被銷燬時,它的析構器都會被執行。
deinit { print("\(name) is no more!") }複製代碼
類和結構體的最後一個區別是它們處理常量的方式。若是你有一個常量結構體,它有一個變量屬性,那麼這個變量屬性是沒法修改的。
可是,若是它是一個常量類,也有一個變量屬性,那麼這個變量屬性是能夠被修改的。基於這個區別,類的方法在改變屬性時,並不須要 mutating
關鍵字,而結構體則須要。
這個區別意味着你能夠修改類中的任何變量屬性,即使類的實例自己被聲明爲常量。如下代碼徹底合法:
class Singer { var name = "Taylor Swift" } let taylor = Singer() taylor.name = "Ed Sheeran" print(taylor.name)複製代碼
若是你不想屬性被修改,那麼你必須直接將屬性聲明爲常量。
class Singer { let name = "Taylor Swift" }複製代碼
讓咱們來總結一下。
final
關鍵字來標記一個類,這樣能夠阻止它被繼承。
個人公衆號
這裏有Swift及計算機編程的相關文章,以及優秀國外文章翻譯,歡迎關注~