初始化是類,結構體和枚舉類型實例化的準備階段。這個階段設置這個實例存儲的屬性的初始化數值和做一些使用實例之前的準備以及必須要做的其他一些設置工作。
?
通過定義構造器(initializers)實現這個實例化過程,也就是創建一個新的具體實例的特殊方法。和Objective-C不一樣的是,Swift的構造器沒有返回值。它們主要充當的角色是確保這個實例在使用之前能正確的初始化。
?
類實例也能實現一個析構器(deinitializer),在類實例銷毀之前做一些清理工作。更多的關于析構器(deinitializer)的內容可以參考Deinitialization。
?
?
1、存儲屬性的初始化
類和結構體必須在它們被創建時把它們所有的屬性設置為合理的值。存儲屬性不能為不確定狀態
?
你可以在構造方法里面給一個屬性設置一個初始值,或者在定義的時候給屬性設置一個默認值,這個行為將會在接下來的章節描述。
注意:當你對給一個屬性分配一個默認值的時候,它會調用它相對應的初始化方法,這個值是對屬性直接設置的,不會通知它對應的觀察者
?
構造器
構造器是創建一個具體類型實例的方法。最簡單的構造器就是一個沒有任何參數實例方法,寫作init。
?
在下面的例子定義了一個叫Fahrenheit(華氏度)的新結構體,來儲存轉換成華氏度的溫度。Fahrenheit結構體,有一個屬性,叫temperature(溫度),它的類型為Double(雙精度浮點數):
struct Fahrenheit { var temperature: Double init() { temperature = 32.0 } } var f = Fahrenheit() println("The default temperature is \(f.temperature)° Fahrenheit") // prints "The default temperature is 32.0° Fahrenheit"
?
這個結構體定義了一個單一的構造方法init,它沒有任何參數,它儲存的溫度屬性初始化為32.0度。(水在華氏度的溫度情況下的冰點)。
?
屬性的默認值
如上所述,你可以在構造器中設置它自己的儲存屬性的初始化值。或者在屬性聲明時,指定屬性的默認值,你指定一個默認的屬性值,會被分配到它定義的初始值。
注意:如果一個屬性常常使用同樣的初始化值 ,提供一個默認值會比在初始化使用一個默認值會更好。
同樣的結果,但是默認值與屬性的初始化在它定義地時候就緊緊地捆綁在一起。很簡單地就能構造器更簡潔,和可以讓你從默認值中推斷出這個屬性的類型。默認值也能讓你優化默認構造器和繼承構造器變得更容易,在本章會稍候描述。
?
你可以在上面的Fahrenheit(華氏度)結構體定義時,給temperature(溫度)屬性提供默認值。
struct Fahrenheit { var temperature = 32.0 }
?
2、自定義初始化(Customizing Initialization)
你可以根據輸入的參數來自定義初始化過程和可選的屬性類型,或者在初始化的時候修改靜態屬性。在這章節將會詳細敘述。
?
初始化參數
你可以在構造器定義的時候提供一部分參數,在自定義初始化過程中定義變量的類型和名稱。
初始化參和函數或者方法參數一樣有著同樣的功能。
?
在下面的例子中,定義了一個結構體Celsius。儲存了轉換成攝氏度的溫度,Celsius結構體實現了從不同的溫度初始化結構體的兩個方法,init(fromFahrenheit:) 和init(fromKelvin:)。
struct Celsius { var temperatureInCelsius: Double = 0.0 init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 } } let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) // boilingPointOfWater.temperatureInCelsius is 100.0 let freezingPointOfWater = Celsius(fromKelvin: 273.15) // freezingPointOfWater.temperatureInCelsius is 0.0
?
第一個構造器只有一個初始化參數,形參(External Parameter Names)fromFahrenheit,和實參(Local Parameter Names)fahrenheit。第二個構造器有一個單一的初始化參數,形參(External Parameter Names)fromKenvin,和實參(Local Parameter Names)kelvin。兩個構造器都把單一的參數轉換為攝氏度和儲存到一個temperatureInCelsius的屬性.
?
實參名(Local Parameter Names)和形參名(External Parameter Names)
和函數參數和方法參數一樣,初始化參數擁有在構造器函數體使用的實參,和在調用時使用的形參.
然而,和函數或者方法不同,構造器在圓括號前面沒有一個識別函數名稱。因此,構造器參數的名稱和類型,在被調用的時候,很大程度上扮演一個被識別的重要角 色。為此,在構造器中,當你沒有提供形參名時,Swift就會為每一個參數提供一個自動的形參名。這個形參名和實參名相同,就像和之前你寫的每一個初始化 參數的hash符號一樣。
注意:如果你在構造器中沒有定義形參,提供一個下橫線(_)作為區分形參和上面說描述的重寫默認行為。
?
在下面的例子 ,定義了一個結構體Color,擁有三個靜態屬性red,green和blue。這些屬性儲存了從0.0到1.0的值,這些值代表紅色 ,綠色和藍色的深度。
Color提供了一個構造器,以及三個雙精度(Double)類型的參數:
struct Color { let red = 0.0, green = 0.0, blue = 0.0 init(red: Double, green: Double, blue: Double) { self.red = red self.green = green self.blue = blue } }
?
無論什么時候,你創建一個Color實例,你必須使用每一個顏色的形參來調用構造器:
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
?
值得注意的是,不能不通過形參名來調用構造器。在構造器定義之后,形參名必須一致使用。如果漏掉就會在編寫時提示錯誤。
let veryGreen = Color(0.0, 1.0, 0.0) // this reports a compile-time error - external names are required
?
可選類型
如果你儲存屬性使用的是自定義的類型在邏輯上允許值為空-或者他們的值并不在構造器中初始化,或者他們被允許為空。可以定義一個可選類型的屬性。可選類型屬性是一個自動初始化值為nil,表示這個屬性有意在構造器中設置為“空值”(no value yet)。
在下面的例子中,定義了一個SurveryQuestion類,擁有一個可選的String屬性response。
?
這個回答在他們調查問題在發布之前是無法知道的,所以response定義為類型String? ,或者叫可選String(optional String)。說明它會被自動分配一個默認值nil,意思為當surverQuestion初始化時還不存在。
?
在初始化時修改靜態屬性
當你在設置靜態屬性值時,只要在初始化完成之前,你都可以在初始化時隨時修改靜態屬性。
注意:對于類的實例化,一個靜態屬性只能在初始化時被修改,這個初始化在類定義時已經確定。
?
你可以重寫SurveryQuestion例子,對于問題的text屬性,使用靜態屬性會比動態屬性要好,因為SurveyQuestion實例被創建之后就無法修改。盡管text屬性現在是靜態的,但是仍然可以在構造器中被設置:
class SurveyQuestion { let text: String var response: String? init(text: String) { self.text = text } func ask() { println(text) } } let beetsQuestion = SurveyQuestion(text: "How about beets?") beetsQuestion.ask() // prints "How about beets?" beetsQuestion.response = "I also like beets. (But not with cheese.)"
?
3、默認構造器
?
Swift為每一個結構或者基類提供了默認的構造器,來初始化它們所包含的所有屬性。默認構造器將會創建一個新的實例然后將它們的屬性設置為默認值。
?
下面的例子定義了一個叫ShoppingListItem的類,包含了名稱,數量和是否已購買的屬性,將會被用在購物清單中:
class ShoppingListItem { var name: String? var quantity = 1 var purchased = false } var item = ShoppingListItem()
?
因為ShoppingListItem類中所有的屬性都有默認值,并且這個類是一個沒有父類的基類,所以它默認擁有一個會將所有包含的屬性設置為初 始值的默認構造器。比如在這個例子中name屬性是一個可選String屬性,它會被默認設置為nil,盡管在代碼中沒有指明。上面的例子使用默認構造器 創建了一個ShoppingListItem類,記做ShoppingListItem(),然后將它賦值給了變量item。
?
結構類型的成員逐一構造器
?
除了上面提到的默認構造器之外,結構類型還有另外一種成員逐一完成初始化的構造器,可以在定義結構的時候直接指定每個屬性的初始值。
?
成員逐一構造器是一種為結構的成員屬性進行初始化的簡便方法。下面的例子定義了一個叫Size的結構,和兩個屬性分別叫width和height。每個屬性都是Double類型的并且被初始化為0.0。
?
因為每個存儲屬性都有默認值,在Size結構創建一個實例的時候就可以自動調用這個成員逐一構造器init(width:height:):
struct Size { var width = 0.0, height = 0.0 } let twoByTwo = Size(width: 2.0, height: 2.0)
?
4、數值類型的構造器代理
?
在實例的初始化過程中,構造器可以調用其他的構造器來完成初始化。這個過程叫構造器代理,可以避免多個構造器的重復代碼。
?
對于數值類型和類來說,構造器代理的工作形式是不一樣的。數值類型(結構和枚舉)不支持繼承,因此他們的構造器代理相對簡單,因為它們只能使用自己 的構造器代理。但是一個類可以繼承自另外一個類,所以類需要確保在初始化的時候將它所有的存儲屬性都設置為正確的值。這種過程在下一節類的繼承和初始化中 敘述。
?
對于數值類型來說,可以使用self.init來調用其他構造器,注意只能在這個數值類型內部調用相應的構造器。
?
需要注意的是如果你為數值類型定義了一個構造器,你就不能再使用默認構造器了。這種特性可以避免當你提供了一個特別復雜的構造器的時候,另外一個人誤使用了默認構造器而出錯。
?
注意:如果你想要同時使用默認構造器和你自己設置的構造器,不要將這兩種構造器寫在一起,而是使用擴展形式。更多內容可以參考Extensions一章。
?
下面的示例定義了一個結構Rect來表示一個幾何中的矩形。這個Rect結構需要另外兩個結構來組成,包括Size和Point,初始值均為0.0:
struct Size { var width = 0.0, height = 0.0 } struct Point { var x = 0.0, y = 0.0 }
?
現在你有三種初始化Rect結構的方式:直接使用為origin和size屬性初始化的0值,給定一個指定的origin和size,或者使用中心點和大小來初始化。下面的例子包含了這三種初始化方式:
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) } }
??
init()構造器和默認構造器的功能相同。這個構造器不需要任何內容,只是用來在已有其他構造器的時候表示默認構造器的依然存在。調用這個構造器 創建的Rect,根據Point和Size的結構定義,Point(x: 0.0, y: 0.0) ,Size(width: 0.0, height: 0.0) origin和size都會被設置為0。
let basicRect = Rect() // basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)
?
第二個Rect構造器init(origin:size:)和成員逐一構造器類似,它使用給定的值來初始化結構的屬性:
let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0)) // originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0)
?
第三個構造器init(center:size)就更加復雜一些,它首先使用center和size計算出了origin的值,然后調用(或者是使用代理)了init(origin:size)構造器,設置origin和size的值:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0)) // centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)
?
init(center:size:)構造器同樣可以設置oringin和size的值,而且使用起來也非常方便,代碼也比較簡潔因為它使用了已有的一些構造器。
?
注意:可以參考Extensions一章,學習怎樣省略init()和init(origin:size:)
?
5、類的繼承和初始化
?
譯者注:本小節內容Apple從底層解釋,十分復雜,建議有需要的讀者自行閱讀英文原文。
?
本小節主要的意思就是說:
?
1、自定義初始化方法要先調用自己類默認初始化方法,自己重寫默認初始化方法要先調用父類默認初始化方法
?
2、應該要先調用父類的構造器或者自身的默認構造器,以防止先給屬性賦值了然后才調用父類或者自身的默認構造器把以前的賦值覆蓋了
?
一個類的所有存儲屬性-包括從父類繼承而來的屬性-都必須在初始化的時候設置初始值。
?
Swift為class類型定義了兩種構造器來確保它們所有的存儲屬性都設置了初始值。這兩種方式叫做指定構造器和便捷構造器。
?
指定構造器和便捷構造器
?
指定構造器是一個類最主要的構造器。指定構造器通過設置所有屬性的初值并且調用所有的父類構造器來根據構造鏈一次初始化所有的屬性。
?
類所擁有的指定構造器很少,一般只有一個,并且是連接這父類的構造鏈依次完成構造的。
?
每個類至少有一個指定構造器,在有些情況下,需要使用繼承來從父類中得到該指定構造器,更多內容可以查看后面的Automatic Initializer Inheritance章節。
?
便捷構造器是類的第二種常用構造器。你可以調用同一個類中的指定構造器來定義一個便捷構造器,使用指定構造器來設置相關的參數默認值。你還可以定義一個便捷構造器來創建這個類的實例或者是別的特殊用途。
?
如果你的類不需要它們,也可以不定義便捷構造器。不過對于常見初始化模型需要快捷方式的時候創建一個便捷構造器可以讓你的初始化過程變成十分簡單便捷。
?
構造鏈
?
為了簡化指定構造器和便捷構造器的關系,Swift為兩種構造器的代理調用設置了三個規則:
?
規則1
?
指定構造器必須調用它直接父類的指定構造器
?
規則2
?
便捷構造器只能調用同一個類中的其它構造器
?
規則3
?
便捷構造器必須以調用一個指定構造器結束
?
記下這些規則的簡單方法是:
?
指定構造器必須向上代理
?
便捷構造器必須橫向代理
?
可以使用下面的圖來表示:
?
?
父類中的兩個便捷構造器依次調用直到指定構造器,子類中的指定構造器調用了父類的指定構造器。
?
注意:這些規則不會影響每個類的實例創建過程。每個構造器都可以用來創建它們各自的類的實例。這些規則只影響你如何編寫類實現代碼。
?
下圖演示的是另一種更為復雜的具有四個等級的類。這個圖展示了指定構造器在類的初始化過程中如何被作為“漏斗”節點的。這個構造鏈簡化了類與類之間的交互關系:
?
?
兩階段的初始化
?
在Swift中,類的初始化要經過兩個階段。在第一個階段,每一個存儲屬性都被設置了一個初始值。一旦每個存儲屬性的值在初始化階段被設置了,在第二個階段,每個類在這個實例被使用之前都會有機會來設置它們相應的存儲屬性。
?
兩階段的模式使初始化過程更加安全,還可以讓每個類在類的層級關系中具有更多的可能性。兩階段初始化方法可以防止屬性在被初始化之前就被使用,或者是被另一個構造器錯誤地賦值。
?
注意:Swift的這種兩階段初始化方法跟Objective-C中的類似。主要的差別是在第一個過程中,Objective-C為每個屬性賦值0或者null,而在Swift中,可以個性化設置這些初始值,還可以處理一些初始值不能是0或者nil的情況。
?
Swift編譯器通過四重檢查來確保兩階段式的初始化過程是完全正確無誤的:
?
?
As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all its own properties are initialized before it hands off up the chain.
?
self
as a value until after the first phase of initialization is complete.
?
The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase.
?
Here’s how two-phase initialization plays out, based on the four safety checks above:
?
Phase 1
?
- A designated or convenience initializer is called on a class.
- Memory for a new instance of that class is allocated. The memory is not yet initialized.
- A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.
- The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.
- This continues up the class inheritance chain until the top of the chain is reached.
- Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.
Phase 2
?
-
Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access
self
and can modify its properties, call its instance methods, and so on. -
Finally, any convenience initializers in the chain have the option to customize the instance and to work with
self
.
Here’s how phase 1 looks for an initialization call for a hypothetical subclass and superclass:
?
?
In this example, initialization begins with a call to a convenience initializer on the subclass. This convenience initializer cannot yet modify any properties. It delegates across to a designated initializer from the same class.
?
The designated initializer makes sure that all of the subclass’s properties have a value, as per safety check 1. It then calls a designated initializer on its superclass to continue the initialization up the chain.
?
The superclass’s designated initializer makes sure that all of the superclass properties have a value. There are no further superclasses to initialize, and so no further delegation is needed.
?
As soon as all properties of the superclass have an initial value, its memory is considered fully initialized, and Phase 1 is complete.
?
Here’s how phase 2 looks for the same initialization call:
?
?
The superclass’s designated initializer now has an opportunity to customize the instance further (although it does not have to).
?
Once the superclass’s designated initializer is finished, the subclass’s designated initializer can perform additional customization (although again, it does not have to).
?
Finally, once the subclass’s designated initializer is finished, the convenience initializer that was originally called can perform additional customization.
?
構造器的繼承和重寫
?
Unlike subclasses in Objective-C, Swift subclasses do not not inherit their superclass initializers by default. Swift’s approach prevents a situation in which a simple initializer from a superclass is automatically inherited by a more specialized subclass and is used to create a new instance of the subclass that is not fully or correctly initialized.
?
If you want your custom subclass to present one or more of the same initializers as its superclass—perhaps to perform some customization during initialization—you can provide an overriding implementation of the same initializer within your custom subclass.
?
If the initializer you are overriding is a designated initializer, you can override its implementation in your subclass and call the superclass version of the initializer from within your overriding version.
?
If the initializer you are overriding is a convenience initializer, your override must call another designated initializer from its own subclass, as per the rules described above in Initializer Chaining .
?
?
NOTE
?
Unlike methods, properties, and subscripts, you do not need to write the
override
keyword when overriding an initializer.
?
構造器自動繼承
?
As mentioned above, subclasses do not not inherit their superclass initializers by default. However, superclass initializers are automatically inherited if certain conditions are met. In practice, this means that you do not need to write initializer overrides in many common scenarios, and can inherit your superclass initializers with minimal effort whenever it is safe to do so.
?
Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply:
?
These rules apply even if your subclass adds further convenience initializers.
?
?
NOTE
?
A subclass can implement a superclass designated initializer as a subclass convenience initializer as part of satisfying rule 2.
?
指定初始化和便捷初始化的語法
?
Designated initializers for classes are written in the same way as simple initializers for value types:
init(parameters) { statements }
?
Convenience initializers are written in the same style, but with the
convenience
keyword placed before the
init
keyword, separated by a space:
convenience init(parameters) { statements }
?
指定初始化和便捷初始化實戰
?
下面的例子演示的是指定構造器,便捷構造器和自動構造器繼承的實戰。例子中定義了三個類分別叫Food,RecipeIngredient和ShoppingListItem,并給出了他們的繼承關系。
?
基類叫做Food,是一個簡單的類只有一個name屬性:
class Food { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "[Unnamed]") } }
?
下圖就是Food類的構造鏈:
?
?
類不存在成員逐一構造器,所以Food類提供了一個指定構造器,使用參數name來完成初始化:
let namedMeat = Food(name: "Bacon") // namedMeat's name is "Bacon"
?
init(name:String)構造器就是Food類中的指定構造器,因為它保證了每一個Food實例的屬性都被初始化了。由于它沒有父類,所以不需要調用super.init()構造器。
?
Food類也提供了便捷構造器init(),這個構造器沒有參數,僅僅只是將name設置為了[Unnamed]:
let mysteryMeat = Food() // mysteryMeat's name is "[Unnamed]"
?
下一個類是Food的子類,叫做RecipeIngredient。這個類描述的是做飯時候的配料,包括一個數量屬性Int類型,然后定義了兩個構造器:
class RecipeIngredient: Food { var quantity: Int init(name: String, quantity: Int) { self.quantity = quantity super.init(name: name) } convenience init(name: String) { self.init(name: name, quantity: 1) } }
?
下圖表示這兩個類的構造鏈:
?
RecipeIngredient類有它自己的指定構造器init(name: String, quantity:Int),用來創建一個新的RecipeIngredient實例。在這個指定構造器中它調用了父類的指定構造器init(name:String)。
?
然后它還有一個便捷構造器,init(name),它使用了同一個類中的指定構造器。當然它還包括一個繼承來的默認構造器init(),這個構造器將使用RecipeIngredient中的init(name: String)構造器。
?
RecipeIngredient
also defines a convenience initializer,
init(name: String)
, which is used to create a
RecipeIngredient
instance by name alone. This convenience initializer assumes a quantity of
1
for any
RecipeIngredient
instance that is created without an explicit quantity. The definition of this convenience initializer makes
RecipeIngredient
instances quicker and more convenient to create, and avoids code duplication when creating several single-quantity
RecipeIngredient
instances. This convenience initializer simply delegates across to the class’s designated initializer.
?
Note that the
init(name: String)
convenience initializer provided by
RecipeIngredient
takes the same parameters as the
init(name: String)
designated
initializer from
Food
. Even though
RecipeIngredient
provides this initializer as a convenience initializer,
RecipeIngredient
has nonetheless provided an implementation of all of its superclass’s designated initializers. Therefore,
RecipeIngredient
automatically inherits all of its superclass’s convenience initializers too.
?
In this example, the superclass for
RecipeIngredient
is
Food
, which has a single convenience initializer called
init()
. This initializer is therefore inherited by
RecipeIngredient
. The inherited version of
init()
functions in exactly the same way as the
Food
version, except that it delegates to the
RecipeIngredient
version of
init(name: String)
rather than the
Food
version.
?
上述三種構造器都可以用來創建RecipeIngredient實例:
let oneMysteryItem = RecipeIngredient() let oneBacon = RecipeIngredient(name: "Bacon") let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
?
最后一個類是ShoppingListItem繼承自RecipeIngredient,它又包括了另外兩個屬性,是否已購買purchased,描述description,描述本身還是一個計算屬性:
class ShoppingListItem: RecipeIngredient { var purchased = false var description: String { var output = "\(quantity) x \(name.lowercaseString)" output += purchased ? " yes" : " no" return output } }
?
注意:ShoppingListItem沒有定義構造器來初始化purchased的值,因為每個商品在買之前purchased都是默認被設置為沒有被購買的。
?
因為ShoppingListItem沒有提供其他構造器,那么它就完全繼承了父類的構造器,用下圖可以說明:
?
你可以在創建ShoppingListItem實例時使用所有的繼承構造器:
var breakfastList = [ ShoppingListItem(), ShoppingListItem(name: "Bacon"), ShoppingListItem(name: "Eggs", quantity: 6), ] breakfastList[0].name = "Orange juice" breakfastList[0].purchased = true for item in breakfastList { println(item.description) } // 1 x orange juice yes // 1 x bacon no // 6 x eggs no
?
通過輸出可以看出所有的實例在創建的時候,屬性的默認值都被正確的初始化了。
?
6、通過閉包或者函數來設置一個默認屬性值
?
如果存儲屬性的默認值需要額外的特殊設置,可以使用閉包或者函數來完成。
?
閉包或者函數會創建一個臨時變量來作為返回值為這個屬性賦值。下面是如果使用閉包賦值的一個示意代碼:
class SomeClass { let someProperty: SomeType = { // create a default value for someProperty inside this closure // someValue must be of the same type as SomeType return someValue }() }
?
需要注意的是在閉包結尾有兩個小括號,告訴Swift這個閉包是需要立即執行的。
?
注意:如果你時候閉包來初始化一個屬性,在閉包執行的時候,后續的一些屬性還沒有被初始化。在閉包中不要訪問任何后面的屬性,一面發生錯誤,也不能使用self屬性,或者其它實例方法。
?
下面的例子是一個叫Checkerboard的結構,是由游戲Checkers來的
?
這 個游戲是在一個10×10的黑白相間的格子上進行的。來表示這個游戲盤,使用了一個叫Checkerboard的結構,其中一個屬性叫 boardColors,是一個100個Bool類型的數組。true表示這個格子是黑色,false表示是白色。那么在初始化的時候可以通過下面的代碼 來初始化:
struct Checkerboard { let boardColors: Bool[] = { var temporaryBoard = Bool[]() var isBlack = false for i in 1...10 { for j in 1...10 { temporaryBoard.append(isBlack) isBlack = !isBlack } isBlack = !isBlack } return temporaryBoard }() func squareIsBlackAtRow(row: Int, column: Int) -> Bool { return boardColors[(row * 10) + column] } }
??
當一個新的Checkerboard實例創建的時候,閉包會執行,然后boardColor的默認值將會被依次計算并且返回,然后作為結構的一個屬性。通過使用squareIsBlackAtRow工具函數可以檢測是否被正確設置:
let board = Checkerboard() println(board.squareIsBlackAtRow(0, column: 1)) // prints "true" println(board.squareIsBlackAtRow(9, column: 9)) // prints "false"?
?
感謝翻譯小組成員:李起攀( 微博 )、若晨( 微博 )、YAO、粽子、山有木兮木有枝、渺-Bessie、墨離、矮人王、CXH、Tiger大顧( 微博 )
原始鏈接
http://letsswift.com/2014/06/initialization
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
