本文是學(xué)習(xí)《The Swift Programming Language》整理的相關(guān)隨筆日裙,基本的語法不作介紹,主要介紹Swift中的一些特性或者與OC差異點(diǎn)麦牺。
系列文章:
- Swift4 基礎(chǔ)部分:The Basics
- Swift4 基礎(chǔ)部分:Basic Operators
- Swift4 基礎(chǔ)部分:Strings and Characters
- Swift4 基礎(chǔ)部分:Collection Types
- Swift4 基礎(chǔ)部分:Control Flow
- Swift4 基礎(chǔ)部分:Functions
- Swift4 基礎(chǔ)部分:Closures
- Swift4 基礎(chǔ)部分: Enumerations
- Swift4 基礎(chǔ)部分: Classes and Structures
- Swift4 基礎(chǔ)部分: Properties
- Swift4 基礎(chǔ)部分: Methods
- Swift4 基礎(chǔ)部分: Subscripts
- Swift4 基礎(chǔ)部分: Inheritance
初始化器(Initializers)
- 直接查看基本的使用例子:
例子:
struct Fahrenheit{
var temperature:Double;
init() {
temperature = 32.0;
}
}
var f = Fahrenheit();
print("The default temperature is \(f.temperature)° Fahrenheit")
執(zhí)行結(jié)果:
The default temperature is 32.0° Fahrenheit
自定義初始化(Customizing Initialization)
例子:
var temperatureInCelsius:Double;
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("The default temperature is \(boilingPointOfWater.temperatureInCelsius)° Fahrenheit")
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
print("The default temperature is \(freezingPointOfWater.temperatureInCelsius)° Fahrenheit")
執(zhí)行結(jié)果:
The default temperature is 100.0° Fahrenheit
The default temperature is 0.0° Fahrenheit
參數(shù)名稱和參數(shù)標(biāo)簽(Parameter Names and Argument Labels)
例子:
struct Color {
let red,green,blue: Double;
init(red:Double,green:Double,blue:Double){
self.red = red;
self.green = green;
self.blue = blue;
}
init(white:Double){
red = white;
green = white;
blue = white;
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
print("magenta red:\(magenta.red) green:\(magenta.green) blue:\(magenta.blue)");
print("halfGray red:\(halfGray.red) green:\(halfGray.green) blue:\(halfGray.blue)");
執(zhí)行結(jié)果:
magenta red:1.0 green:0.0 blue:1.0
halfGray red:0.5 green:0.5 blue:0.5
不需要參數(shù)標(biāo)簽的初始化器(Initializer Parameters Without Argument Labels)
直接看例子:
struct Celsius{
var temperatureInCelsius:Double;
init(fromFahrenheit fahrenheit:Double){
temperatureInCelsius = (fahrenheit - 32.0) / 1.8;
}
init(fromKelvin kelvin:Double){
temperatureInCelsius = kelvin - 273.15;
}
// 此處就是具體的體現(xiàn)
init(_ celsius:Double){
temperatureInCelsius = celsius;
}
}
let bodyTemperature = Celsius(37.0);
print(bodyTemperature.temperatureInCelsius);
執(zhí)行結(jié)果:
37.0
可選屬性類型(Optional Property Types)
If your custom type has a stored property that is
logically allowed to have “no value”—perhaps because its
value cannot be set during initialization, or because it
is allowed to have “no value” at some later point—declare
the property with an optional type.
- 如果你定制的類型是允許取值為空的存儲型屬性--不管是因?yàn)樗鼰o法在初始化時(shí)賦值钮蛛,還是因?yàn)樗梢栽谥竽硞€(gè)時(shí)間點(diǎn)可以賦值為空--你都需要將它定義為可選類型。
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()
cheeseQuestion.response = "Yes, I do like cheese."
執(zhí)行結(jié)果:
Do you like cheese?
構(gòu)造過程中常量屬性的修改(Assigning Constant Properties During Initialization)
- 只要在構(gòu)造過程結(jié)束前常量的值能確定剖膳,你可以在構(gòu)造過程中的任意時(shí)間點(diǎn)修改常量屬性的值魏颓。
- 對某個(gè)類實(shí)例來說,它的常量屬性只能在定義它的類的構(gòu)造過程中修改吱晒;不能在子類中修改甸饱。
例子:
class SurveyQuestion {
let text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
class DetailSurveyQuestion:SurveyQuestion{
init(content content: String){
self.text = content;
}
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// 輸出 "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"
執(zhí)行結(jié)果:編譯錯(cuò)誤驗(yàn)證上述結(jié)論2
Playground execution failed: error: MyPlayground.playground:900:19: error: cannot assign to property: 'text' is a 'let' constant
self.text = content;
~~~~~~~~~ ^
去掉子類的實(shí)現(xiàn),執(zhí)行結(jié)果:
How about beets?
默認(rèn)構(gòu)造器(Default Initializers)
Swift provides a default initializer for any structure or
class that provides default values for all of its
properties and does not provide at least one initializer
itself.
- Swift 將為所有屬性已提供默認(rèn)值的且自身沒有定義任何構(gòu)造器的結(jié)構(gòu)體或基類仑濒,提供一個(gè)默認(rèn)的構(gòu)造器叹话。
例子:
class ShoppingListItem {
var name: String?;
var quantity = 1;
var purchased = false;
}
var item = ShoppingListItem();
結(jié)構(gòu)體的逐一成員構(gòu)造器(Memberwise Initializers for Structure Types)
Structure types automatically receive a memberwise
initializer if they do not define any of their own custom
initializers. Unlike a default initializer, the structure
receives a memberwise initializer even if it has stored
properties that do not have default values.
- 結(jié)構(gòu)體類型可以自動接收逐一成員構(gòu)造器,如果他們沒有定義任何的構(gòu)造器。
例子:
struct Size {
var width = 0.0, height = 0.0;
}
let size = Size(width:2.0, height:2.0);
print("size \(size.width) \(size.height)");
執(zhí)行結(jié)果:
size 2.0 2.0
值類型的構(gòu)造器代理(Initializer Delegation for Value Types)
Initializers can call other initializers to perform part
of an instance’s initialization. This process, known as
initializer delegation, avoids duplicating code across
multiple initializers.
- 構(gòu)造器可以通過調(diào)用其它構(gòu)造器來完成實(shí)例的部分構(gòu)造過程墩瞳。這一過程稱為構(gòu)造器代理驼壶,它能避免多個(gè)構(gòu)造器間的代碼重復(fù)。
例子:
struct Size {
var width = 0.0, height = 0.0;
}
struct Point {
var x = 0.0, y = 0.0;
}
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);
}
}
let originReact = Rect(origin:Point(x:2.0,y:2.0),size:Size(width:5.0,height:5.0));
print("point:\(originReact.origin) size:\(originReact.size)");
執(zhí)行結(jié)果:
point:Point(x: 2.0, y: 2.0) size:Size(width: 5.0, height: 5.0)
類的繼承與構(gòu)造過程(Class Inheritance and Initialization)
Swift defines two kinds of initializers for class types to
help ensure all stored properties receive an initial
value. These are known as designated initializers and
convenience initializers.
- Swift 提供了兩種類型的類構(gòu)造器來確保所有類實(shí)例中存儲型屬性都能獲得初始值喉酌,它們分別是指定構(gòu)造器和便利構(gòu)造器热凹。
指定構(gòu)造器和便利構(gòu)造器的語法(Syntax for Designated and Convenience Initializers)
指定構(gòu)造器語法:
init(parameters) {
statements
}
便利構(gòu)造器語法:
convenience init(parameters) {
statements
}
類的構(gòu)造器代理(Initializer Delegation for Class Types)
基本規(guī)則:
Designated initializers must always delegate up.
Convenience initializers must always delegate across.
- 指定構(gòu)造器必須總是向上代理泵喘。
- 便利構(gòu)造器必須總是橫向代理。
構(gòu)造器的繼承與重載(Initializer Inheritance and Overriding)
When you write a subclass initializer that matches a
superclass designated initializer, you are effectively
providing an override of that designated initializer.
Therefore, you must write the override modifier before the
subclass’s initializer definition.
- 可以在子類中通過關(guān)鍵字
override
重載父類的構(gòu)造器方法般妙。
例子:
class Vehicle {
var numberOfWheels = 0;
var description:String {
return "\(numberOfWheels) wheel(s)";
}
}
class Bicycle:Vehicle {
override init() {
super.init();
numberOfWheels = 2;
}
}
let bicycle = Bicycle();
print("Bicycle: \(bicycle.description)");
執(zhí)行結(jié)果:
Bicycle: 2 wheel(s)
指定構(gòu)造器和便利構(gòu)造器實(shí)戰(zhàn)(Designated and Convenience Initializers in Action)
直接看一下指定構(gòu)造器與便利構(gòu)造器的實(shí)際應(yīng)用的例子:
class Food {
var name: String;
init(name: String) {
self.name = name;
}
convenience init() {
self.init(name: "[Unnamed]");
}
}
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);
}
}
class ShoppingListItem: RecipeIngredient {
var purchased = false;
var description: String {
var output = "\(quantity) x \(name)";
output += purchased ? " ?" : " ?";
return output;
}
}
var breakfastList = [
ShoppingListItem(),
ShoppingListItem(name: "Bacon"),
ShoppingListItem(name: "Eggs", quantity: 6),
];
breakfastList[0].name = "Orange juice";
breakfastList[0].purchased = true;
for item in breakfastList {
print(item.description);
}
執(zhí)行結(jié)果:
1 x Orange juice ?
1 x Bacon ?
6 x Eggs ?
可失敗的構(gòu)造器(Failable Initializers)
It is sometimes useful to define a class, structure, or
enumeration for which initialization can fail. This
failure might be triggered by invalid initialization
parameter values, the absence of a required external
resource, or some other condition that prevents
initialization from succeeding.
- 如果一個(gè)類纪铺,結(jié)構(gòu)體或枚舉類型的對象,在構(gòu)造自身的過程中有可能失敗碟渺,則為其定義一個(gè)可失敗構(gòu)造器鲜锚,是非常有用的。這類錯(cuò)誤可能是參數(shù)或者確實(shí)外部資源等苫拍。
例子:
struct Animal {
let species:String;
init?(species: String){
if species.isEmpty{
return nil;
}
self.species = species;
}
}
let someCreature = Animal(species: "Giraffe");
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)");
}
執(zhí)行結(jié)果:
An animal was initialized with a species of Giraffe
枚舉類型的可失敗構(gòu)造器(Failable Initializers for Enumerations)
例子:
enum TemperatureUnit {
case kelvin, celsius, fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .kelvin
case "C":
self = .celsius
case "F":
self = .fahrenheit
default:
return nil
}
}
}
let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
// Prints "This is a defined temperature unit, so initialization succeeded."
let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so initialization failed.")
}
執(zhí)行結(jié)果:
This is a defined temperature unit, so initialization succeeded.
This is not a defined temperature unit, so initialization failed.
帶原始值的枚舉類型的可失敗構(gòu)造器(Failable Initializers for Enumerations with Raw Values)
例子:
enum TemperatureUnit: Character {
case kelvin = "K", celsius = "C", fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so initialization failed.")
}
執(zhí)行結(jié)果:
This is a defined temperature unit, so initialization succeeded.
This is not a defined temperature unit, so initialization failed.
構(gòu)造失敗的傳遞(Propagation of Initialization Failure)
A failable initializer of a class, structure, or
enumeration can delegate across to another failable
initializer from the same class, structure, or
enumeration. Similarly, a subclass failable initializer
can delegate up to a superclass failable initializer.
- 可失敗構(gòu)造器在同一類芜繁,結(jié)構(gòu)體和枚舉中橫向代理其他的可失敗構(gòu)造器。類似的怯疤,子類的可失敗構(gòu)造器也能向上代理基類的可失敗構(gòu)造器浆洗。
例子:
class Product {
let name: String;
init?(name: String) {
if name.isEmpty { return nil; }
self.name = name;
}
}
class CartItem: Product {
let quantity: Int;
init?(name: String, quantity: Int) {
if quantity < 1 { return nil; }
self.quantity = quantity;
super.init(name: name);
}
}
if let twoSocks = CartItem(name: "sock", quantity: 2) {
print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)");
}
if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)");
} else {
print("Unable to initialize zero shirts");
}
if let oneUnnamed = CartItem(name: "", quantity: 1) {
print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)");
} else {
print("Unable to initialize one unnamed product");
}
執(zhí)行結(jié)果:
Item: sock, quantity: 2
Unable to initialize zero shirts
Unable to initialize one unnamed product
覆寫父類的可失敗的構(gòu)造器(Overriding a Failable Initializer)
You can override a superclass failable initializer in a subclass, just like any other initializer.
- 就如同其它構(gòu)造器一樣,你也可以用子類的可失敗構(gòu)造器覆蓋基類的可失敗構(gòu)造器集峦。
例子:
class Document {
var name: String?;
init() {};
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class AutomaticallyNamedDocument: Document {
override init() {
super.init();
self.name = "[Untitled]";
}
override init(name: String) {
super.init();
if name.isEmpty {
self.name = "[Untitled]";
} else {
self.name = name;
}
}
}
必須存在的構(gòu)造器(Required Initializers)
Write the required modifier before the definition of a
class initializer to indicate that every subclass of the
class must implement that initializer:
class SomeClass {
required init() {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init() {
// subclass implementation of the required initializer goes here
}
}
通過閉包和函數(shù)來設(shè)置屬性的默認(rèn)值(Setting a Default Property Value with a Closure or Function)
If a stored property’s default value requires some
customization or setup, you can use a closure or global
function to provide a customized default value for that
property.
- 如果某個(gè)存儲型屬性的默認(rèn)值需要特別的定制或準(zhǔn)備伏社,你就可以使用閉包或全局函數(shù)來為其屬性提供定制的默認(rèn)值。
例子:
struct Chessboard {
let boardColors:[Bool] = {
var temporaryBoard = [Bool]();
var isBlack = false;
for i in 1...8 {
for j in 1...8 {
temporaryBoard.append(isBlack);
isBlack = !isBlack;
}
}
isBlack = !isBlack;
return temporaryBoard;
}()
func squareIsBlackAt(row:Int,column:Int) -> Bool{
return boardColors[row * 8 + column];
}
}
let board = Chessboard();
print(board.squareIsBlackAt(row: 0, column: 1));
print(board.squareIsBlackAt(row: 7, column: 7));
執(zhí)行結(jié)果:
true
true