初始化(Initilization)是設(shè)置類型的實例的操作。它為每個存儲屬性給定了一個初始值, 并且可能會牽涉其它準(zhǔn)備工作。這個處理之后, 這個實例就準(zhǔn)備好了并且可用了。
初始化時, 屬性的值要么是給定的默認存儲值, 要么是根據(jù)需要計算得到的值。
初始化函數(shù)的語法
結(jié)構(gòu)體和類要求在初始化完成后, 它們的存儲屬性擁有初始值。這個要求解釋了為什么你一直給你所有的存儲屬性設(shè)置默認值。如果你還沒給你的這些存儲屬性默認值, 那么編譯器就會給你報錯并告訴你該類型的屬性還沒有被準(zhǔn)備好使用。在類型上定義一個初始化函數(shù)是另外一種保證在實例被創(chuàng)建之后屬性有值的方式。
初始化函數(shù)的定義和你看過的函數(shù)有點不一樣, 初始化函數(shù)不是以 func關(guān)鍵字開頭, 盡管它也是類型中的方法。初始化函數(shù)的語法看起來像這樣:
struct CustomType {
init(someValue: SomeType) {
// 這兒是初始化代碼
}
}
這個通用的語法在結(jié)構(gòu)體、枚舉和類之間沒什么不同。在上面的例子中, 初始化函數(shù)有一個叫做 someValue類型為 SomeType 的參數(shù)。而初始化函數(shù)通常有一個或多個參數(shù), 它們也可以含有 0 個 參數(shù)。(這時 init關(guān)鍵字后面有一組空括號)
不像其它方法, 初始化函數(shù)不返回值。相反, 初始化函數(shù)的任務(wù)是給類型的每個存儲屬性設(shè)定上值。
結(jié)構(gòu)體初始化
結(jié)構(gòu)體即可以有默認初始化函數(shù)又可以有自定義初始化函數(shù)。當(dāng)你使用結(jié)構(gòu)體的時候, 你通常會利用提供好的默認初始化函數(shù), 但是也有其它你會自定義初始化處理的情況。
結(jié)構(gòu)體的默認初始化函數(shù)
還記得你是怎么獲得你的Town類型的實例的嗎? 你給Town類型的存儲屬性設(shè)置了默認值。你不知道的是你使用了一個由 Swift 自動提供的空的初始化函數(shù)。(一個不含參數(shù)的初始化函數(shù))。 當(dāng)你鍵入像 var myTown = Town() , 那么這個語法就會調(diào)用空的初始化函數(shù)并給新的實例的屬性設(shè)置上你指定的默認值。
另外一種形式的默認初始化函數(shù)就是逐個成員初始化函數(shù)(memberwise initializer)。逐個成員初始化函數(shù)中類型的每個存儲屬性都有一個參數(shù)。 這時, 你不會讓編譯器根據(jù)你指定的默認值來填充新的實例的屬性的值。相反, 免費的逐個成員初始化函數(shù)會包含所有需要值的存儲屬性。(我們稱之為免費的, 是因為它是 Swift 編譯器自動提供的 — 你不需要定義它)。
記住, 初始化的一個準(zhǔn)則就是給新的實例的所有存儲屬性設(shè)置上值以準(zhǔn)備使用。編譯器會強制要求你的新的實例中的所有存儲屬性都有值。如果你沒有為你的自定義的結(jié)構(gòu)體提供初始化函數(shù), 你必須通過默認值或逐個成員初始化函數(shù)提供必要的值。
// 使用逐個成員初始化函數(shù)
struct Town {
var population = 5422
var numberOfStoplights = 4
// 實例方法
func printTownDescription() {
print("Population: \(population); number of stoplights: \(numberOfStoplights)")
}
}
var myTown() = Town(population: 10000, numberOfStoplights: 6)
myTown.printTownDescription()
注意, Town 的屬性 population 和 numberOfStoplights 有默認值。 這些默認值不同于你提供給 Town 的逐個成員初始化函數(shù)的參數(shù)值?,F(xiàn)在打印出:
Population: 10000; number of stoplights: 6
這些屬性的值是怎么改變默認值的呢?
myTown這個實例現(xiàn)在是用免費的逐個成員初始化函數(shù)創(chuàng)建的。這個 Town 類型的所有存儲屬性列出在初始化函數(shù)里面, 它允許你為實例屬性指定新的值。就像你看到的, 你傳給初始化函數(shù)的新值替換掉了默認的值。
注意, Town 的屬性名被用作了該初始化函數(shù)的外部參數(shù)名。Swift 自動地為每個初始化函數(shù)提供默認的外部參數(shù)名, 每個參數(shù)一個。這個約定很重要, 因為 Swift 中所有的初始化函數(shù)都含有相同的名字: init。因此, init 這個函數(shù)名不能用于識別應(yīng)該調(diào)用哪個指定初始化函數(shù)。參數(shù)的名字加上參數(shù)的類型才能幫助編譯器區(qū)分不同的初始化函數(shù), 以至于它能知道該調(diào)用哪個初始化函數(shù)。
默認的結(jié)構(gòu)體的逐個成員初始化函數(shù)是有用的, 因為 Swift 自動為你提供了它們。你免費獲得了它們。結(jié)構(gòu)體的這個優(yōu)點讓結(jié)構(gòu)體特別吸引人。然而, 通常你想自定義你的類型的初始化函數(shù)。這就輪到自定義初始化函數(shù)了。
為結(jié)構(gòu)體自定義初始化函數(shù)
現(xiàn)在輪到你為 Town 類型寫你自己的初始化函數(shù)了。自定義的初始化函數(shù)很強大, 而越強大則責(zé)任越多。當(dāng)你寫了自己的初始化函數(shù)時, Swift 就不會給你免費的初始化函數(shù)了(和默認的逐個成員初始化函數(shù)告別把)。你要為自己確保實例的所有屬性都有給定的合適值負責(zé)。
現(xiàn)在打掃下房間, 把屬性的默認值移除掉(默認值只是告訴你每個實例的屬性都要有值, 現(xiàn)在該我們自己動手實現(xiàn)了)。
struct Town {
let region: String
var population: Int
var numberOfStoplights
func printTownDescription() {
print("Population: \(population); number of stoplights: \(numberOfStoplights); region: \(region)")
}
}
現(xiàn)在是時候創(chuàng)建你的自定義初始化函數(shù)了。之后, 你會從這個類型中定義的其它初始化函數(shù)調(diào)用這個初始化函數(shù)?,F(xiàn)在, 為你的 Town 類型添加如下初始化函數(shù)。
// 添加一個逐個成員初始化函數(shù)
...
var numberOfStoplights: Int
init(region: String, population: Int, stoplights: Int) {
self.region = region
self.population = population
numberOfStoplights = stoplights
}
init(region:population:stoplights:) 方法接收了3個參數(shù), 每一個參數(shù)都是為 Town 類型中的存儲屬性設(shè)置新值。你接收初始化函數(shù)的參數(shù)的值并把它們傳遞給類型實際的屬性。例如, 傳遞給初始化函數(shù)的 region參數(shù)的值被設(shè)置為 region屬性的值。因為初始化函數(shù)中的參數(shù)名和屬性的名字相同, 你需要通過 self顯式地訪問該屬性。numberOfStoplights屬性就沒有這個問題, 所以你僅僅把初始化函數(shù)的 stoplights參數(shù)的值設(shè)置給 numberOfStoplights屬性。
注意, 你給 region 屬性設(shè)置了值, 即使它被聲明為一個常量。Swift編譯器允許你在初始化期間的某個點那兒初始化一個常量屬性。記住, 初始化的目的是為了保證類型的屬性在初始化完成后都有值。
之前編譯器給你提供的免費逐個成員初始化函數(shù)的參數(shù)使用是實際的屬性名 numberOfStoplights。在 Town 這個初始化函數(shù)中, 你把參數(shù)名縮短為 stoplights。
var myTown = Town(region: "West", population: 10000, stoplights: 6)
初始化函數(shù)的代理
你可以在同一個類型中定義一個初始化函數(shù)來調(diào)用其它初始化函數(shù)。這個過程叫做初始化函數(shù)的代理。它通常用于為創(chuàng)建類的實例時提供多個路徑。
在值類型中(例如枚舉和結(jié)構(gòu)體), 初始化函數(shù)代理相對直接。因為值類型不支持繼承, 初始化函數(shù)代理只涉及調(diào)用類型定義的其它初始化函數(shù)。對于類來說就有點復(fù)雜了。你很快就會看到。
init(region: String, population: Int, stoplights: Int) {
self.region = region
self.population = population
numberOfStoplights = stoplights
}
// 初始化函數(shù)代理(它自己做不了, 但是通過別人來完成初始化)
init(population: Int, stoplights: Int) {
self.init(region: "N/A", population: population, stoplights: stoplights)
}
你在self上調(diào)用了其它初始化函數(shù)。你傳遞了 population 和 stoplights 參數(shù), 但是沒有 region 參數(shù), 所以你必須提供自己 region 值, 這兒, 你指定了字符串"N/A".
初始化函數(shù)代理能幫助減少代碼的重復(fù)。
這就是為什么我們說初始化函數(shù)代理“定義路徑”。
因為你定義了你自己的逐個成員初始化函數(shù), 編譯器不會再給你提供免費的初始化函數(shù)。這不是有所限制, 它甚至是一種優(yōu)點。例如, 你可能想使用這個新的初始化函數(shù), 如果給定的 town 沒有 region 信息可以獲得時。那樣, 你會使用你創(chuàng)建的新的帶有參數(shù)的初始化函數(shù)為 population 和 stoplights 設(shè)置對應(yīng)的屬性而給 region一個占位符值。
// 使用初始化函數(shù)代理
var myTown = Town(population: 10000, stoplights: 6)
myTown.printTownDescription()
類的初始化
類的繼承給初始化增添了某些復(fù)雜性。
特別的地方是, 類添加了指定初始化函數(shù)和便利初始化函數(shù)的概念。類中的初始化函數(shù)要么是指定初始化函數(shù), 要么是便利初始化函數(shù)。指定初始化函數(shù)負責(zé)確保實例的所有屬性在初始化完成之前都有值, 因此讓實例可以準(zhǔn)備好被使用。
便利初始化函數(shù)是輔助指定初始化函數(shù)的。它們通過調(diào)用類的指定初始化函數(shù)來補充指定初始化函數(shù)。便利初始化函數(shù)的角色通常是創(chuàng)建特定用途的類的實例。
類的默認初始化函數(shù)
如果你為所有屬性提供默認值并且不寫你自己的初始化函數(shù), 那么類會獲得一個默認的, 空的初始化函數(shù)。類不會像結(jié)構(gòu)體那樣獲得一個免費的逐個成員初始化函數(shù)。這解釋了之前你為什么給類設(shè)置默認值: 它允許你利用免費的空初始化函數(shù)。因此, 你能獲得 Zombie 類的實例, 像這樣: let fredTheZombie = Zombie(), 空的圓括號表明你正在使用默認的類初始化函數(shù)。
初始化和類的繼承
class Monster {
var town: Town?
var name: String // 如果不設(shè)置初始值, 就得指定變量的類型
init(town: Town?, monsterName: String) {
self.town = town
name = monsterName
}
}
這個初始化函數(shù)有兩個參數(shù): 一個是 Town類型的 optional 實例, 另外一個是 monster 的名字。在初始化函數(shù)的實現(xiàn)中, 這些參數(shù)的值被賦值給類的屬性。 再一次, 注意初始化函數(shù)中的參數(shù) town 于類的屬性名town 匹配, 所以你必須通過 self訪問該屬性并給它賦值。但是你不必通過 self訪問 name屬性, 因為初始化函數(shù)的參數(shù)有一個不同的名字。
自動初始化函數(shù)繼承
類通常不繼承它們的父類的初始化函數(shù)。Swift 的這個特征的目的是阻止子類無心地提供一個初始化函數(shù)但是卻沒有為子類的所有屬性設(shè)置上值, 因為子類中常常添加父類中不存在的額外屬性。要求子類擁有自己的初始化函數(shù)幫助防止使用不徹底的初始化函數(shù)進行部分初始化。
然而, 存在類確實自動繼承它的父類的初始化函數(shù)的情況。如果你的子類為添加的所有新的屬性提供了默認值, 那么存在兩個類會繼承它的父類的初始化函數(shù)的場景。
- 如果子類沒有定義任何指定初始化函數(shù), 它會繼承它的父類的指定初始化函數(shù)
- 如果子類實現(xiàn)了父類所有的指定初始化函數(shù) — 不管是顯式的還是通過繼承的, 它會繼承它的父類的所有便利初始化函數(shù)。
你的Zombie 類型就是適應(yīng)于第一個場景。它繼承了 Monster類型的唯一的指定初始化函數(shù), 因為它為它添加的所有屬性提供了默認值并且它沒有定義它自己的指定初始化函數(shù)。這個初始化函數(shù)的簽名是 init(town:monsterName:)。還有, 因為 Zombie 類型繼承了一個初始化函數(shù), 編譯器不再提供你之前使用過的免費初始化函數(shù)。
因此, 從編譯器的角度來看, Zombie 類沒有一個空的初始化函數(shù)可用。并且, 僅此作答, Zombie 類的初始化函數(shù)缺少 town 這個參數(shù)。
class Zombie: Monster {
var walksWithLimp = true
// final 用來防止子類重寫父類的方法, 僵尸的行為都是一致的。子類不能改寫
final override func terrorizeTown() {
town?.changePopulation(-10) // 僵尸一出來就吃掉 10 個人, town 屬性繼承自父類 Monster
super.terrorizeTown() // super 關(guān)鍵字專門用于繼承, 所以枚舉和結(jié)構(gòu)體中沒有。
}
func changeName(name: String, walksWithLimp: Bool) {
self.name = name
self.walksWithLimp = walksWithLimp
}
}
let fredTheZombie = Zombie(town: myTown, monsterName: "Fred")
現(xiàn)在, 當(dāng)你創(chuàng)建 Monster 或 Zombie 類型的一個實例時, 你給該實例的 town 和 name 屬性賦上值。
類的指定初始化函數(shù)
類使用指定初始化函數(shù)作為它們的主初始化函數(shù)。作為這個角色的一部分, 指定初始化函數(shù)負責(zé)確保在初始化結(jié)束之前該類的屬性都被賦了值。如果類擁有一個父類, 那么它的指定初始化函數(shù)必須調(diào)用它的父類的指定初始化函數(shù)。
你已經(jīng)為 Monster 類寫了一個指定初始化函數(shù)。 回憶下前面:
init(town: Town?, monsterName: String) {
self.town = town
name = monsterName
}
指定初始化函數(shù)是未經(jīng)裝飾的, 意思是指定初始化函數(shù)的 init 關(guān)鍵字前面沒有特殊的關(guān)鍵字。這個語法區(qū)分了指定初始化函數(shù)和便利初始化函數(shù), 便利初始化函數(shù)的 init 關(guān)鍵字前面使用了關(guān)鍵字 convenience。
Monster 類的初始化函數(shù)保證了在初始化結(jié)束前它的所有屬性都給定了值。 目前, Zombie 類型為它的所有屬性(除了繼承自 Monster 的那些屬性)給定了默認值。因此, 你為 Monster 類定義的初始化函數(shù)用在 Zombie 里面也工作的很好。然而, 如果 Zombie 定義了它自己的初始化函數(shù)的話會更好, 以至于你能自定義它的初始化函數(shù)。
現(xiàn)在移除 Zombie 類的屬性的默認值。
class Zombie: Monster {
var walksWithLimp: Bool
private(set) var isFallingApart: Bool
// final 用來防止子類重寫父類的方法, 僵尸的行為都是一致的。子類不能改寫
final override func terrorizeTown() {
town?.changePopulation(-10) // 僵尸一出來就吃掉 10 個人, town 屬性繼承自父類 Monster
super.terrorizeTown() // super 關(guān)鍵字專門用于繼承, 所以枚舉和結(jié)構(gòu)體中沒有。
}
func changeName(name: String, walksWithLimp: Bool) {
self.name = name
self.walksWithLimp = walksWithLimp
}
}
移除掉這些默認值觸發(fā)了編譯器錯誤: 類 Zombie 沒有初始化函數(shù)。如果沒有賦值默認的值, Zombie 類需要一個初始化函數(shù)來在初始化完成前給它的屬性賦上值。
為 Zombie 類添加一個新的初始化函數(shù)來解決這個問題。
class Zombie: Monster {
override class var spookyNoise: String {
return "Brains..."
}
var walksWithLimp: Bool
private(set) var isFallingApart: Bool
init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) {
walksWithLimp = limp
isFallingApart = fallingApart
super.init(town: town, monsterName: monsterName)
}
final override func terrorizeTown() {
if !isFallingApart {
town?.changePopulation(-10)
}
super.terrorizeTown()
}
}
你的新的初始化函數(shù)消除了錯誤, 因為你現(xiàn)在保證了 Zombie 的屬性在初始化結(jié)尾時都有值了。 這里你添加了兩部分。首先, 新的初始化函數(shù)通過 limp 和 fallingApart 參數(shù)給 walksWithLimp 和 isFallingApart屬性設(shè)置了值。這倆個屬性是Zombie 類所特有的, 所以指定初始化函數(shù)使用合適的值初始化了它們。
其次, 你調(diào)用了Zombie 的父類的指定初始化函數(shù)。就像第 15 章那樣, super指的是子類的父類。因此, 語法 super.init(town: town, monsterName: monsterName)把Zombie 類的初始化函數(shù)中的 town 和 monsterName 參數(shù)的值傳遞給 Monster 類的指定初始化函數(shù)。這樣做就調(diào)用了Monster 類的初始化函數(shù), 它會確保 Zombie 中的 town 和 name 屬性被設(shè)置上值。查看圖17.3:

你可能想知道為什么在最后調(diào)用父類的初始化函數(shù)。因為 Zombie 的初始化函數(shù)是 Zombie 類的指定初始化函數(shù), 它負責(zé)初始化它所引入的所有屬性。這些屬性被賦值之后, 子類的指定初始化函數(shù)負責(zé)調(diào)用它的父類的初始化函數(shù)以使父類能初始化它的屬性。(先做好自己的, 再去要求別人。)
// let fredTheZombie = Zombie(town: myTown, monsterName: "Fred")
// 替換為
let fredTheZombie = Zombie(
limp: false,
fallingApart: false,
town: myzTown,
monsterName: "Fred"
)
類的便利初始化函數(shù)
不像指定初始化函數(shù), 便利初始化函數(shù)并不負責(zé)確保類的所有屬性都有值。相反, 它們僅僅處理它們被定義去做的那部分工作, 然后把信息傳遞給其它便利初始化函數(shù)或指定初始化函數(shù)。所有的便利初始化函數(shù)在同一個類中調(diào)用其它的初始化函數(shù)。最終, 便利初始化函數(shù)必須調(diào)用到類的指定初始化函數(shù)那兒。給定類中便利初始化函數(shù)和指定初始化函數(shù)的關(guān)系:類的存儲屬性接收初始化值, 定義一個路徑。
在 Zombie 類型上弄一個便利初始化函數(shù)。它會省略 town 和 monsterName 參數(shù), 意思是這個初始化函數(shù)的調(diào)用者將會只需要為這個初始化函數(shù)的參數(shù)提供參數(shù)負責(zé)。
// 使用便利初始化函數(shù)
...
init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) {
walksWithLimp = limp
isFallingApart = fallingApart
super.init(town: town, monsterName: monsterName)
}
convenience init(limp: Bool, fallingApart: Bool) {
self.init(limp: limp, fallingApart: fallingApart, town: nil, monsterName: "Fred")
if walksWithLimp {
print("This zombie has a bad knee.")
}
}
final override func terrorizeTown() {
if !isFallingApart {
town?.changePopulation(-10)
}
} ...
你使用 convenience關(guān)鍵字把一個初始化函數(shù)標(biāo)記為便利初始化函數(shù)。這個關(guān)鍵字告訴編譯器該初始化函數(shù)將會需要代理給該類的其它初始化函數(shù), 最終調(diào)用一個指定初始化函數(shù)。這次調(diào)用之后, 該類的實例將會能夠使用。
然而, 該便利初始化函數(shù)在 Zombie 類上調(diào)用指定初始化函數(shù)。它傳遞形參接收到的值: limp和fallingApart。 對于便利初始化函數(shù)沒有接收到的形參的值, town和 monsterName, 你傳遞了一個 “nil” 和 "Fred" 給 Zombie 的指定初始化函數(shù)。
一旦便利初始化函數(shù)調(diào)用了指定初始化函數(shù), 那么該類的實例就完全準(zhǔn)備好使用了。因此你可以檢查實例的 walksWithLimp 屬性的值。如果你嘗試在調(diào)用 Zombie 的指定初始化函數(shù)之前檢查這樣做, 那么編譯器就會報錯: 在 self.init 被調(diào)用之前, 代理初始化函數(shù)中使用了 self。這個錯誤告訴你代理初始化函數(shù)正嘗試使用 self, 而它需要訪問 walksWithLimp屬性, 在它被準(zhǔn)備好使用之前。

你現(xiàn)在可以使用這個便利初始化函數(shù)創(chuàng)建Zombie 類型的實例。
let convenientZombie = Zombie(limp: true, failingApart: fasle)
類的必須的初始化函數(shù)
類可以要求它的子類提供指定的初始化函數(shù)。例如, 假如你想要所有的 Monster 子類提供 monster 的 name 值和 town 值(或者 nil, 如果沒有找到一個 town 的話)。要這樣的話, 使用 required關(guān)鍵字來標(biāo)記一個初始化函數(shù)以讓給類型的子類必須提供指定的初始化函數(shù)。
// 使 town 和 monsterName 是必須的
class Monster {
var victimPool: Int {
...
}
required init(town: Town?, monsterName: String) {
self.town = town
name = monsterName
}
func terrorizeTown() {
...
}
}
Monster 類的唯一指定初始化函數(shù)現(xiàn)在是必須的。子類必須實現(xiàn)這個初始化函數(shù)。
這樣的話子類中會報錯, 因為你還未在Zombie子類中實現(xiàn)這個新要求的初始化函數(shù)。
// 在 Zombie.swift 中添加必須的初始化函數(shù)
...
convenience init(limp: Bool, fallingApart: Bool) {
self.init(limp: limp, fallingApart: fallingApart, town: nil, monsterName: "Fred")
if walksWithLimp {
print("This zombie has a bad knee.")
}
}
required init(town: Town?, monsterName: String) {
walksWithLimp = flase
isFallingApart = false
super.init(town: town, monsterName: monsterName)
}
final override func terrorizeTown() {
if !isFallingApart {
town?.changePopulation(-10)
}
super.terrorizeTown()
}
...
要實現(xiàn)一個父類的必須要求的初始化函數(shù), 在子類的初始化函數(shù)前置一個 required關(guān)鍵字。 不像其它函數(shù)那樣, 如果是繼承自你的父類必須重寫, 你不必用 override關(guān)鍵字標(biāo)記初始化函數(shù)。它由 required關(guān)鍵字隱式的標(biāo)記了。
你的這個 required初始化函數(shù)的實現(xiàn)讓它成為 Zombie 類的一個指定初始化函數(shù)。為什么? 你問? 好問題。
回想指定初始化函數(shù)負責(zé)初始化類型的屬性,還負責(zé)向上代理給父類的初始化函數(shù)。這個實現(xiàn)正是做了那兩件事情。你因此能夠使用這個初始化函數(shù)來實例化Zombie 類。
這個時候, 你可能想知道, Zombie 有多少個指定初始化函數(shù)?答案是兩個。init(limp:fallingApart:town:monsterName:) 和 init(town:monsterName)。有多個指定初始化函數(shù)是完全可以的, 并沒有什么不尋常。
Deinitialization
反初始化是從內(nèi)存中移除類的實例的部分處理, 當(dāng)它們不再需要時。從概念上講, 它是初始化的對立面。反初始化被限于引用類型。這對值類型不可用, 因為當(dāng)它們從作用域中移除后就從內(nèi)存中移除了。
在 Swift 中, 反初始化函數(shù)在實例被移出內(nèi)存前被立即調(diào)用。在實例被釋放內(nèi)存之前它提供了一個機會用于做任何最后的維護。
一個類只有一個反初始化函數(shù)。反初始化函數(shù)以init關(guān)鍵字開頭, 不接收任何參數(shù)。讓我們看一個例子:
...
required init(town: Town?, monsterName: String) {
walksWithLimp = false
isFallingApart = false
super.init(town: town, monsterName: monsterName)
}
...
func changeName(name: String, walksWithLimp: Bool) {
... }
deinit {
print("Zombie named \(name) is no longer with us.")
}
...
注意反初始化函數(shù)訪問了Zombie 的name 屬性。 反初始化函數(shù)可以訪問到實例的全部屬性和方法。
fredTheZombie = nil