/**
1.存儲型屬性的初始賦值
2.定製化構造過程
3.默認構造器
4.值類型的構造代理
5.類的繼承和構造過程
6.通過閉包和函數來設置屬性的默認值
與OC不同,swift的構造器無需返回值
*/
//存儲型屬性的初始賦值
/**
爲存儲型屬性設置默認值或者在構造器中爲其賦值時,它們的值是被直接設置的,不會觸發任何屬性觀察器
*/
//構造器
struct Fahrenheit {
var temperature: Double;
init() {
temperature = 32.0;
}
}
var f = Fahrenheit();
print(f.temperature);
f.temperature = 10.0;
print(f.temperature);
//默認屬性值
/**
可以在屬性聲明時設置默認值
如果一個屬性總是使用同一個初始值,可以爲其設置一個默認值。無論定義默認值還是在構造器中賦值,最終他們實現的效果是一樣的,只不過默認值跟屬性構造過程結合的更緊密。使用默認值能讓你的造成器更簡潔清晰,且能通過默認值自動推到出屬性的類型,同時,也能充分利用默認構造器,構造器繼承等特性
*/
struct Fahrenheit2 {
var temperature = 24.0;
}
var f2 = Fahrenheit2();
print(f2.temperature);
//定製化構造過程
/**
可以通過輸入參數和可選屬性類型來定製構造過程,也可以在構造過程中修改常量屬性
*/
//構造參數
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);
print(boilingPointOfWater.temperatureInCelsius);
let freezingPointOfWater = Celsius(fromKelvin: 273.15);
print(freezingPointOfWater.temperatureInCelsius);
//內部和外部參數名
/**
跟函數和方法參數相同,構造參數也存在一個在構造器內部使用的參數名字和一個在調用構造器時使用的外部參數名字
在定義時,沒有提供參數的外部名字時,swift會爲每個構造器的參數自動生成一個跟內部名字相同的外部名
乳溝不希望提供外部參數名,可以用_來覆蓋默認行爲
*/
struct Color {
var 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;
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0);
//可選屬性類型
/**
如果定製的類型包含一個邏輯上允許取值爲空的存儲型屬性,不管是因爲它無法在初始化時賦值,還是因爲它可以在之後某個時間點可以賦值爲空,都需要定義爲可選類型
*/
class SurveyQuestion {
var text: String;
var response: String?;
init(text: String) {
self.text = text;
}
func ask() {
print(text);
}
}
let cheeseQuestion = SurveyQuestion(text: "do you like cheese?");
cheeseQuestion.ask();
print(cheeseQuestion.response);
cheeseQuestion.response = "Yes, i do like cheese."
print(cheeseQuestion.response!);
//構造過程中常量屬性的修改
/**
只要在構造過程結束前常量的值能確定,可以在構造過程中的任意時間點修改常量屬性的值
對某個類實例來說,它的常量屬性只能在定義它的類的構造過程中修改,不能在子類中修改
*/
class SurveyQuestion2 {
let text: String;
var response: String?;
init(text: String) {
self.text = text;
}
func ask() {
print(self.text);
}
}
let beetsQuestion = SurveyQuestion2(text: "how about beets?")
beetsQuestion.ask();
beetsQuestion.response = "i also like beets.";
print(beetsQuestion.response!);
//默認構造器
class ShoppingListItem {
var name: String?;
var quantity = 1;
var purchased = false;
}
var item = ShoppingListItem();
//結構體的逐一成員構造器
struct Size {
var width = 0.0, height = 0.0;
}
let twoByTwo = Size(width: 2.0, height: 2.0);
//值類型的構造器代理
/**
構造器可以通過調用其他構造器來完成實例的部分構造過程。這一過程稱爲構造器代理,能減少多個構造器間的代碼重複
構造器代理的實現規則和形式在值類型和類類型中有所不同。
值類型(結構體和枚舉類型)不支持繼承,所以構造器代理的過程相對簡單,因爲它只能代理任務給本身提供的其他構造器,類則不同,它可以繼承自其它類,這意味着類有責任保證所有繼承的存儲型屬性在構造時也能正確的初始化
對於值類型,可以使用self.init在自定義的構造器中引用其他的屬於相同值類型的構造器,並且只能在構造器內部調用self.init
如果某個值類型定義了一個定製的構造器,將無法訪問到默認構造器,可以防止在爲值類型定義了一個更復雜的,完成了重要準備構造器之後,別人還是錯誤使用了那個自動生成的構造器
*/
struct Size2 {
var width = 0.0, height = 0.0;
}
struct Point {
var x = 0.0, y = 0.0;
}
struct Rect {
var origin = Point();
var size = Size2();
init() {};
init(origin: Point, size: Size2) {
self.origin = origin;
self.size = size;
}
init(center: Point, size: Size2) {
let originX = center.x - size.width / 2;
let originY = center.y - size.height / 2;
self.init(origin: Point(x: originX, y: originY), size: size);
}
func description() {
print("origin is \(self.origin.x, self.origin.y), and size is \(self.size.width, self.size.height)");
}
}
let basicRect = Rect();
basicRect.description();
let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size2(width: 5.0, height: 5.0));
originRect.description();
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size2(width: 3.0, height: 3.0));
centerRect.description();
//類的繼承和構造過程
/**
類裏面的所有存儲型屬性,包括所有繼承自父類的屬性,都必須在構造過程中設置初始值
swift提供了兩種類型的類構造器來確保所有類實例中存儲屬性都能獲得初始值,分別是指定構造器和便利構造器
*/
//指定構造器和便利構造器
/**
指定構造器是類中最主要的構造器。一個指定構造器將初始化類中提供的所有屬性,並根據父類鏈往上調用父類的構造器來實現父類的初始化
每一個類都必須擁有至少一個指定構造器,在某些情況下,許多通過繼承了父類中的指定構造器而滿足了這個條件
便利構造器是累中比較次要的,輔助性的構造器。可以定義便利構造器來調用同一個類中的指定構造器,併爲其參數提供默認值。也可以定義便利構造器來創建一個特殊用途或特定輸入發實例
在必要的時候爲類提供便利構造器,能夠節省更多開發時間並讓類的構造過程更清晰明瞭
*/
//構造器鏈
/**
爲了簡化指定構造器和便利構造器之間的調用關係,swift採用以下三條規則來限制構造器之間的代理調用
1.指定構造器必須調用其直接父類的指定構造器
2.便利構造器必須調用同一類中定義的其它構造器
3.便利構造器必須最終以調用一個指定構造器結束
即指定構造器必須總是向上代理,便利構造器必須總是橫向代理
這些規則不會影響使用時,如何用類去創建實例,任何構造器都可以用來完整創建對應類的實例,這些規則只在實現類的定義時有影響
*/
//指定構造器語法
/**
init(parameters) {
statements
}
*/
//便利構造器語法
/**
需要在init關鍵字之前放置convenience關鍵字
convenience init(parameters) {
statements
}
*/
class Food {
var name: String;
init(name: String) {
self.name = name;
}
convenience init() {
self.init(name: "[Unnamed]");
}
}
let name1 = Food();
print(name1.name);
let nameMeat = Food(name: "Bacon");
print(nameMeat.name);
class RecipeIngredient: Food {
var quantity: Int;
init(name: String, quantity: Int) {
self.quantity = quantity;
super.init(name:name);
}
override convenience init(name: String) {
self.init(name: name, quantity: 1);
}
}
let oneMysteryItem = RecipeIngredient();
print(oneMysteryItem.name, oneMysteryItem.quantity);
let oneBacon = RecipeIngredient(name: "Bacon");
print(oneBacon.name, oneBacon.quantity);
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6);
print(sixEggs.name, sixEggs.quantity);
class ShoppingListItem2: RecipeIngredient {
var purchased = false;
var description: String {
var output = "\(quantity) * \(name.lowercaseString)";
output += purchased ? "Y" : "N";
return output;
}
}
var breakfastList = [ShoppingListItem2(), ShoppingListItem2(name: "Bacon"), ShoppingListItem2(name: "Eggs", quantity: 6)];
breakfastList[0].name = "orange juice";
breakfastList[0].purchased = true;
for item in breakfastList {
print(item.description);
}
//通過閉包和函數來設置屬性的默認值
/**
如果某個存儲型屬性的默認值需要特別的定製或準備,你就可以使用閉包或全局函數來爲其屬性提供定製的默認值。每當某個屬性所屬的新類型實例創建時,對應的閉包或函數會被調用,而它們的返回值會當做默認值賦值給這個屬性
這種類型的閉包或函數一般創建一個跟屬性類型相同的臨時變量,然後修改它的值以滿足預期的初始狀態,最後將這個臨時變量的值作爲屬性的默認值進行返回
class SomeClass {
let someProperty: SomeType = {
}
// 在這個閉包中給 someProperty 創建一個默認值 // someValue 必須和 SomeType 類型相同 return someValue
}()
}
注意閉包結尾的大括號後面接了一個小括號,這是用來告訴swift需要立刻執行此閉包,如果忽略這對括號,相當於是將閉包本身作爲值賦值給了屬性,而不是將閉包的返回值賦值給屬性
如果使用閉包來初始化屬性的值,請記住在閉包執行時,實例的其它部分都還沒有初始化,這意味着你不能夠在閉包裏訪問其它的屬性,就算這個屬性有默認值也不允許。同樣,也不能使用隱式的self屬性,或者調用其它的實例方法
*/
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, colum: Int) -> Bool {
return boardColors[(row * 10) + colum];
}
}
let board = Checkerboard();
print(board.squareIsBlackAtRow(0, colum: 1));
print(board.squareIsBlackAtRow(9, colum: 9));