高屋建瓴
這節(jié)的基礎內(nèi)容主要參考官檔Swift-The Basics,主要涵蓋Swift中的常量,注釋催烘,各種變量沥阱,錯誤處理以及斷言等的說明。
涉及到的概念比較多伊群,這里先總結(jié)下作為Swift本章主要講到的知識點考杉。加粗的元組和optionals類型是Swift和OC相比特有的兩個類型。
- 常量和變量
- 注釋
- 分號
- 整數(shù)
- 浮點數(shù)
- 類型安全和判斷
- 數(shù)值型字面量
- 數(shù)值類型轉(zhuǎn)換
- 類型別名
- 布爾值
-
元組
-
optionals類型
- 錯誤處理
- 斷言
各個擊破
常量和變量
1.使用let定義常量/使用var定義變量
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
2.多個常量或變量定義用逗號隔開
let maximumNumberOfLoginAttempts = 10, minNumberOfLoginAttempts = 1
var x = 0.0, y = 0.0, z = 0.0
3.變量類型標注
//聲明關(guān)鍵字 + 變量名 + ":" + 變量類型
var welcomeMessage: String
//正確使用
welcomeMessage = "hello world"
//報錯
welcomeMessage = 3
但是呢舰始,你會發(fā)現(xiàn)在現(xiàn)實開發(fā)中我們往往很少給變量加類型說明崇棠,因為往往我們在定義的時候習慣給它初始化。
It’s rare that you need to write type annotations in practice. If you provide an initial value for a constant or variable at the point that it’s defined, Swift can almost always infer the type to be used for that constant or variable, as described in Type Safety and Type Inference. In the
welcomeMessage
example above, no initial value is provided, and so the type of thewelcomeMessage
variable is specified with a type annotation rather than being inferred from an initial value.
你很少需要在實踐中使用類型標注丸卷。如果我們再定義常量/變量的時候提供初始化枕稀,Swift總是可以推斷出用于該常量/變量的類型。但是正如 Type Safety and Type Inference所描述的及老,變量"welcomeMessage"并沒有在定義的時候初始化抽莱,所以這個時候變量"welcomeMessage"的類型Swift就不能根據(jù)初始化的值推斷,而是依賴于變量的類型標注(: String).
4.變量命名原則
- a. 不能包含空格骄恶,數(shù)學符號食铐,箭頭符,專用的unicode值
- b. 不能以數(shù)字開頭
- c. 駝峰
這點僧鲁,基本所有語言都有共性虐呻。
5.變量打印
// Prints "The current value of friendlyWelcome is Bonjour!"
print("The current value of friendlyWelcome is \(friendlyWelcome)")
可以看出,這種打印方式還是很特別的寞秃。我們之前OC是使用NSLog做打印斟叼,雖然名稱上與C有錯不同。但是春寿,打印方式上還是一脈相承朗涩,都需要在字符串打印格式中中使用占位符,然后再在格式之后按順序跟著要打印的變量名绑改。
//C
printf("hello these are %s and %s", "wen", "chaors");
//OC
NSLog(@"hello these are %@ and %@", @"wen", @"chaors");
//Swift
print("hello these are \("wen") and \("chaors")")
顯然谢床,Swift在打印格式中直接使用轉(zhuǎn)義符(\)并將變量包裝在小括號()內(nèi),使得打印看上去更加簡潔兄一。不過,剛從C/OC過來的我開始階段還是稍有不適识腿。
注釋
1.和大多數(shù)語言雷同的注釋方式
//單行注釋
/*
多行注釋
第1行
第2行
...
*/
2.嵌套塊注釋
/* This is the start of the first multiline comment.
/* This is the second, nested multiline comment. */
This is the end of the first multiline comment. */
這其實沒什么可說的出革,不過增加這個支持后,對含有塊注釋的代碼進行注釋就方便多了渡讼。也許這樣說還是不太明朗骂束,我們拿OC舉個例子。
嵌套注釋就是針對這種情況的解決方案成箫,其實有時候還是蠻有用的展箱。
分號
想必我們也已經(jīng)發(fā)現(xiàn),前面寫的Swift示例代碼語句結(jié)尾都沒有分號伟众。
Unlike many other languages, Swift doesn’t require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. However, semicolons are required if you want to write multiple separate statements on a single line.
不像其他語言析藕,Swift并不要求在代碼的每個語句之后添加分號(;).當然如果你愿意,你也可以這樣做凳厢。但是账胧,當一行有多個語句時就必須使用分號了。
C語言的編譯器規(guī)定先紫,每句代碼必須使用";"作為分隔符治泥,以便使編譯器知道該語句執(zhí)行到哪里結(jié)束。OC作為C的衍生語言遮精,當然也將這一特點繼承過來居夹。但是,事實上本冲,并不是所有的語言需要這樣做准脂。除了今天的Swift,單行一句代碼不需要加分號的還有Js檬洞,Python等狸膏。
其實,在這個問題上有一個ASI(Automatic semicolon insertion)規(guī)則添怔。簡言之湾戳,就是分號自動插入。很多時候广料,并不是不需要分號砾脑,而是這件事編譯器給我們做了。關(guān)于ASI具體的分析可以看這篇文章
整數(shù)
1.和OC的概念基本相同艾杏,提供API訪問范圍
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
2.int/uint
On a 32-bit platform, Int(Uint) is the same size as Int32(Uint32).
On a 64-bit platform, Int (Uint) is the same size as Int64(Uint64).
浮點數(shù)
Double represents a 64-bit floating-point number. 15位精度
Float represents a 32-bit floating-point number. 6位精度
類型安全和判斷
就是前面講變量初始化和賦值時涉及到的韧衣,編譯器會根據(jù)你給變量傳遞的數(shù)值類型來推斷變量具體的類型。
這里,需要注意一個細節(jié):
- 1.對整數(shù)推斷默認是int
- 2.對浮點數(shù)推斷默認是double
數(shù)值型字面量
1.整數(shù)型字面量:
- 十進制: 正常模式(無前綴)
- 二進制: + 0b 前綴
- 八進制: + 0o 前綴
- 十六進制:+ 0x 前綴
eg:
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
2.科學計數(shù)法
- 1.25e2 1.25 x 10的平方
- 0xfp-2 15 x 10的-2次方
數(shù)值類型轉(zhuǎn)換
1.整數(shù)轉(zhuǎn)換
let cannotBeNegative: UInt8 = -1
// UInt8 cannot store negative numbers, and so this will report an error
let tooBig: Int8 = Int8.max + 1
// Int8 cannot store a number larger than its maximum value,
// and so this will also report an error
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
和其他語言一樣畅铭,某類型整數(shù)表示的數(shù)不能超過它能表示的范圍萧求;其次,不同類型的兩個數(shù)需要轉(zhuǎn)換為相同類型再進行加減法運算顶瞒。
2.浮點數(shù)與轉(zhuǎn)換
let integerPi = Int(pi)
通過轉(zhuǎn)換接口轉(zhuǎn)換。
類型別名
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min // means UInt16.min
// maxAmplitudeFound is now 0
就是可以給固有的數(shù)據(jù)類型起一個別名元旬,至于用處榴徐,文檔是這樣描述的:
Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source.
當你想在特定上下文通過更合適的名稱來引用現(xiàn)有類型時,別名就顯得很有用匀归。例如從外部源處理特定大小的數(shù)據(jù)時坑资。
what?關(guān)于這一點的設計哲學穆端,說實話超哥不是很明白袱贮。或者只是為了代碼上語義看上去更加明確和鮮明体啰?
布爾值
et orangesAreOrange = true
let turnipsAreDelicious = false
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
基本上和OC一樣攒巍,但是這里有一點需要注意。就是整數(shù)類型和布爾值的轉(zhuǎn)換荒勇,在OC里if里int只要是非0值就會認為對應的布爾值為真柒莉,按真的邏輯處理。例如下面的代碼可以運行的:
NSInteger i = 0-1;
if (i) {
NSLog(@"complie succ");
}
但是沽翔,在Swift里布爾值的定義是嚴格的兢孝,上面的寫法會提示i不是一個布爾值,因而導致編譯不通過仅偎。
元組
Tuples是一個OC里沒有的概念跨蟹。它的定義是這樣的:
Tuples group multiple values into a single compound value. The values within a tuple can be of any type and don’t have to be of the same type as each other.
元組將多個值組合為一個復合值。其中的類型可以是任意類型橘沥,并且他們可以是不同類型窗轩。
1.??
let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")
這個??的元組用來描述http狀態(tài)代碼。404代表錯誤碼威恼,"Not Found"代表錯誤的描述信息品姓。將一個int和string復合為一個元組來表示http的狀態(tài)信息。
2.表示和使用
//1.一般表示
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// prints "The status code is 404"
print("The status message is \(statusMessage)")
// prints "The status message is Not Found"
//2.按需使用箫措,不用的用_代替
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// prints "The status code is 404"
//3.按索引訪問
print("The status code is \(http404Error.0)")
// prints "The status code is 404"
print("The status message is \(http404Error.1)")
// prints "The status message is Not Found"
//4.為元組元素命名腹备,按名訪問
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
// prints "The status code is 200"
print("The status message is \(http200Status.description)")
// prints "The status message is OK"
方法2讓我想起了go語言中數(shù)組和字典的遍歷,只需要訪問值不需要下標的時候也是可以使用_占位即可斤蔓。
方法3說明其內(nèi)部的存儲類似于數(shù)組植酥,也是一個有序的順序結(jié)構(gòu)。
Optionals類型
這又是一個Swift特有的類型。
You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all.
optionals類型用于處理值可能缺失的情況友驮∑颍可選意味著:
- 這里有一個值,并且你可以打開可選項訪問他
- 根本就不存在值
The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structures, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there’s a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants.
這一段大概是說optionals類似于OC里的nil卸留,但是nil只能用來表示對象走越,不能表示一般數(shù)據(jù)類型。但optionals可以用于這些類型耻瑟。
1.nil 只有optional類型才能被賦值為nil
// optional類型
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value
//普通int類型
var i = 345
// 這樣賦值編譯器會報錯:can not assign to value
I = nil
2.optional類型的展開
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
// prints "convertedNumber has an integer value of 123."
if let actualNumber = Int(possibleNumber) {
print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
print("\'\(possibleNumber)\' could not be converted to an integer")
}
4.隱式展開optional
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark
Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.
有時optional類型在設置值之后旨指,將始終擁有該值。在這個情況下喳整,不需要每次訪問都檢查和解包谆构。
使用"!"而不是"?"框都,即隱式自動解包(將其值暴露)搬素。實際上,這種情況就和一般變量的使用一樣了魏保。
錯誤處理
本質(zhì)上還是try-catch那一套熬尺。關(guān)于錯誤處理,后面還有專門的章節(jié)詳述囱淋。
func canThrowAnError() throws {
// this function may or may not throw an error
}
do {
try canThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
斷言
斷言和先決條件猪杭,這也是我們都熟悉的。他們是在運行時發(fā)生的檢查妥衣,如果斷言里或先決條件里的布爾值為真皂吮,則代碼照常執(zhí)行;否則税手,程序的當前狀態(tài)無效蜂筹,代碼執(zhí)行將結(jié)束。
The difference between assertions and preconditions is in when they’re checked: Assertions are checked only in debug builds, but preconditions are checked in both debug and production builds. In production builds, the condition inside an assertion isn’t evaluated. This means you can use as many assertions as you want during your development process, without impacting performance in production.
斷言和先決條件的不同之處在于他們什么時候做檢查:斷言只在 debug 構(gòu)建的時候檢查芦倒,但先決條件則在 debug 和生產(chǎn)構(gòu)建中生效艺挪。在生產(chǎn)構(gòu)建中,斷言中的條件不會被計算兵扬。這就是說你可以在開發(fā)的過程當中隨便使用斷言而無需擔心影響生產(chǎn)性能麻裳。
1.斷言的使用
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 is not >= 0.
if age > 10 {
print("You can ride the roller-coaster or the ferris wheel.")
} else if age >= 0 {
print("You can ride the ferris wheel.")
} else {
assertionFailure("A person's age can't be less than zero.")
}
2.強制先決條件
// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")
preconditionFailure("Index can't be less than zero.")
3. fatalError用于標注暫時還沒實現(xiàn)的方法
fatalError("Unimplemented")
至此,這一節(jié)就告一段落了器钟。
---------------------------------------------------------20190519.13.24午后
有時候
堅持你最不想干的事
反而能得到你最想要的東西
但是
如果可以給這種不想干
注入一種激情
那么得到的會不會更多呢津坑?
-----------------------------非著名八線互聯(lián)網(wǎng)九流程序猿 chaors