[極速Swift教程之八] 類

更多內容,歡迎關注公衆號: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!」。

 

Final 類

儘管類繼承十分有用,而且蘋果的平臺在許多地方要求你大量使用它,有的時候你會但願阻止其餘開發者基於你的類構建新的類。

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"複製代碼

因爲類的工做機制,singersingerCopy 指向內存裏的同一個對象。因此當咱們打印 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"
}複製代碼

 

總結

讓咱們來總結一下。

  1. 類和結構體很類似,它們都容許你建立本身的屬性和方法。
  2. 一個類能夠繼承自另外一個類,它會得到父類的全部屬性和方法。談到類層次結構的時候,咱們常常說一個類基於另外一個類,也就是一個類繼承自另外一個類。
  3. 你能夠用 final 關鍵字來標記一個類,這樣能夠阻止它被繼承。
  4. 方法重寫使得一個子類能夠用全新的實現來替代父類中的實現。
  5. 當兩個變量指向同一個實例時,它們指代的對象在內存中佔用同一塊區域,改變其中一個也會改變另外一個。
  6. 類能夠有析構器,它們是類的實例被銷燬時執行的代碼。
  7. 類不像結構體那樣受常量的強制約束。若是類的一個屬性被聲明爲變量,那麼不管類的實例是否以變量的方式建立,這個屬性均可以被修改。

 

個人公衆號

這裏有Swift及計算機編程的相關文章,以及優秀國外文章翻譯,歡迎關注~

相關文章
相關標籤/搜索