Swift基礎(chǔ)語法
一.變量和常量
1.定義
-
let
定義常量,一經(jīng)賦值不允許再修改 -
var
定義變量核无,賦值之后仍然可以修改
//: # 常量
//: 定義常量并且直接設(shè)置數(shù)值
let x = 20
//: 常量數(shù)值一經(jīng)設(shè)置团南,不能修改炼彪,以下代碼會(huì)報(bào)錯(cuò)
// x = 30
//: 使用 `: 類型`,僅僅只定義類型拷橘,而沒有設(shè)置數(shù)值
let x1: Int
//: 常量有一次設(shè)置數(shù)值的機(jī)會(huì)喜爷,以下代碼沒有問題,因?yàn)?x1 還沒有被設(shè)置數(shù)值
x1 = 30
//: 一旦設(shè)置了數(shù)值之后术幔,則不能再次修改诅挑,以下代碼會(huì)報(bào)錯(cuò)泛源,因?yàn)?x1 已經(jīng)被設(shè)置了數(shù)值
// x1 = 50
//: # 變量
//: 變量設(shè)置數(shù)值之后俩由,可以繼續(xù)修改數(shù)值
var y = 200
y = 300
2.自動(dòng)推導(dǎo)
- Swift能夠根據(jù)右邊的代碼幻梯,推導(dǎo)出變量的準(zhǔn)確類型
- 通常在開發(fā)時(shí)碘梢,不需要指定變量的類型
- 如果要指定變量煞躬,可以在變量名后使用:逸邦,然后跟上變量的類型
重要技巧:Option + Click 可以查看變量的類型
3.沒有隱式轉(zhuǎn)換B萍酢G沤啤裹芝!
- Swift 對(duì)數(shù)據(jù)類型要求異常嚴(yán)格
- 任何時(shí)候嫂易,都不會(huì)做隱式轉(zhuǎn)換
如果要對(duì)不同類型的數(shù)據(jù)進(jìn)行計(jì)算掐禁,必須要顯式的轉(zhuǎn)換
let x2 = 100
let y2 = 10.5
let num1 = Double(x2) + y2
let num2 = x2 + Int(y2)
4.let & var 的選擇
-
應(yīng)該盡量先選擇常量穆桂,只有在必須修改時(shí)灼芭,才需要修改為
var
- 在 Xcode 中彼绷,如果沒有修改變量茴迁,Xcode 會(huì)提示修改為
let
二.Optional 可選類型
1.介紹
-
Optional
是 Swift 的一大特色,也是 Swift 初學(xué)者最容易困惑的問題 - 定義變量時(shí)猜旬,如果指定是
可選的
倦卖,表示該變量可以有一個(gè)指定類型的值怕膛,也可以是 nil
- 定義變量時(shí)褐捻,在類型后面添加一個(gè)
?
,表示該變量是可選的 - 變量可選項(xiàng)的默認(rèn)值是
nil
- 常量可選項(xiàng)沒有默認(rèn)值景馁,主要用于在構(gòu)造函數(shù)中給常量設(shè)置初始數(shù)值
// Optional 可能有兩個(gè)值 (None / Some)
// 格式(1. 自動(dòng)推導(dǎo)):var 變量名: Optional = 值
let x: Optional = 20
// 格式(2. 使用泛型):var 變量名:Optional<類型> = 值
let y: Optional<Int> = 30
// 格式(3. 簡(jiǎn)化格式):var 變量名: 類型? = 值
let z: Int? = 10
// 可選值在參與計(jì)算前,必須`解包 unwarping`
// 只有`解包(unwrap)`后才能參與計(jì)算
// 在變量后添加一個(gè) `!`慕购,可以強(qiáng)行解包
// `?` 是用于定義的
// `!` 是用于解包的茬底,程序員要對(duì)每一個(gè) `!` 負(fù)責(zé)
print(x! + y! + z!)
- 如果 Optional 值是
nil
阱表,不允許參與計(jì)算 - 只有
解包(unwrap)
后才能參與計(jì)算 - 在變量后添加一個(gè)
!
最爬,可以強(qiáng)行解包
注意:必須要確保解包后的值不是 nil爱致,否則會(huì)報(bào)錯(cuò)
// 常量可選項(xiàng)必須要設(shè)置初始值
let x: Int? //= 20
x = nil
// 變量可選項(xiàng)默認(rèn)值是 nil
var y: Int? //= 10
y = 20
// unexpectedly found nil while unwrapping an Optional value
// 在對(duì)可選項(xiàng)解包時(shí)發(fā)現(xiàn) nil糠悯,會(huì)報(bào)錯(cuò)互艾!
if y == nil || x == nil {
print("y 或 x 為 nil")
} else {
print(x! + y!)
}
常見錯(cuò)誤
unexpectedly found nil while unwrapping an Optional value
翻譯
在對(duì)可選項(xiàng)[解包]時(shí)發(fā)現(xiàn) nil
2.??
運(yùn)算符 (空合并運(yùn)算符)
-
??
運(yùn)算符可以用于判斷變量/常量
的數(shù)值是否是nil
纫普,如果是則使用后面的值替代 - 在使用 Swift 開發(fā)時(shí)昨稼,
??
能夠簡(jiǎn)化代碼的編寫
var num: Int?
let r1 = (num ?? 0) + 10
print(r1)
三.控制流
1.if
- Swift 中沒有 C 語言中的
非零即真
概念 - 在邏輯判斷時(shí)必須顯示地指明具體的判斷條件
true
/false
- if 語句條件的
()
可以省略 - 但是
{}
不能省略
func demo1(num: Int) -> () {
if num > 10 {
print("大 \(num)")
} else {
print("小 \(num)")
}
}
2.三目運(yùn)算
- Swift 中的
三目
運(yùn)算保持了和 OC 一致的風(fēng)格
func demo2() -> () {
var a = 10
var b = 20
let c = a > b ? a : b
print(c)
}
適當(dāng)?shù)剡\(yùn)用三目悦昵,能夠讓代碼寫得更加簡(jiǎn)潔
3.可選項(xiàng)判斷
- 由于可選項(xiàng)的內(nèi)容可能為
nil
但指,而一旦為nil
則不允許參與計(jì)算 - 因此在實(shí)際開發(fā)中,經(jīng)常需要判斷可選項(xiàng)的內(nèi)容是否為
nil
- 如果單純使用 if连躏,會(huì)讓代碼嵌套層次很深贞滨,讓代碼不宜閱讀和維護(hù)晓铆,為了解決這一問題,蘋果提供了以下三種方式
- ??
- if
let / var
- guard
let / var
else
4.if let / var
func demo3(name: String?, age: Int?) {
// 方法1: 強(qiáng)行解包 - 一旦出現(xiàn) nil 值尚困,程序崩潰
// print(name! + String(age!) + "歲")
// 方法2:使用 if let 判斷
// 使用 `if let`事甜,這種方式逻谦,表明一旦進(jìn)入 if 分支跨跨,n & a 就不在是可選項(xiàng)
// n 和 a 的作用域僅在 `{}` 內(nèi)部
// 可以使用 `,` 同時(shí)判斷多個(gè)可選項(xiàng)是否為空
if let n = name, let a = age {
print(n + String(a) + "歲")
} else {
print("姓名或者年齡為 nil")
}
// 方法3: 使用同名參數(shù)囱皿,避免給變量再次起名的煩惱
if let name = name, let age = age {
print(name + String(age) + "歲")
}
}
5.guard
-
guard
是與if let
相反的語法勇婴,Swift 2.0 推出的
func demo4(name: String?, age: Int?) {
guard let name = name, let age = age else {
print("姓名或者年齡為 nil")
return
}
print(name + String(age) + "歲")
}
- 在程序編寫時(shí),條件檢測(cè)之后的代碼相對(duì)是比較復(fù)雜的
- 使用 guard 的好處
- 能夠判斷每一個(gè)值
- 在真正的代碼邏輯部分嘱腥,省略了一層嵌套
6.switch
-
switch
不再局限于整數(shù) -
switch
可以針對(duì)任意數(shù)據(jù)類型
進(jìn)行判斷 - 不再需要
break
- 每一個(gè)
case
后面必須有可以執(zhí)行的語句 - 要保證處理所有可能的情況耕渴,不然編譯器直接報(bào)錯(cuò),不處理的條件可以放在
default
分支中 - 每一個(gè)
case
中定義的變量?jī)H在當(dāng)前case
中有效齿兔,而 OC 中需要使用{}
let score = "優(yōu)"
switch score {
case "優(yōu)":
let name = "學(xué)生"
print(name + "80~100分")
case "良": print("70~80分")
case "中": print("60~70分")
case "差": print("不及格")
default: break
}
- switch 中能夠賦值和使用
where
關(guān)鍵字添加賦加條件
let point = CGPoint(x: 10, y: 10)
switch point {
case let p where p.x == 0 && p.y == 0:
print("中心點(diǎn)")
case let p where p.x == 0:
print("Y軸")
case let p where p.y == 0:
print("X軸")
case let p where abs(p.x) == abs(p.y):
print("對(duì)角線")
default:
print("其他")
}
- 如果只希望進(jìn)行條件判斷橱脸,賦值部分可以省略
switch score {
case _ where score > 80: print("優(yōu)")
case _ where score > 60: print("及格")
default: print("其他")
}
四.for 循環(huán)
基礎(chǔ)循環(huán)
Range 和開閉區(qū)間
_
可以表示忽略C 風(fēng)格的循環(huán) (Swift 2.2 中過時(shí),Swift 3.0中被舍棄)
var sum = 0
for var i = 0; i < 10; i++ {
sum += I
}
print(sum)
-
for-in
添诉,0..<10
表示[0,10)
sum = 0
for i in 0..<10 {
sum += I
}
print(sum)
- 范圍
0...10
表示[0,10]
sum = 0
for i in 0...10 {
sum += I
}
print(sum)
注意:
..<
和...
用于定義Range
類型,左右都不要添加空格
格式:
for 變量 in 范圍 { // 代碼 }
- 省略下標(biāo)
-
_
能夠匹配任意類型 -
_
表示忽略對(duì)應(yīng)位置的值
-
for _ in 0...10 {
print("hello")
}
五.字符串
1.字符串演練
遍歷字符串中的字符
for s in str.characters {
print(s)
}
字符串長(zhǎng)度
let str = "hello world你好世界"
// 1. 返回指定編碼的字節(jié)長(zhǎng)度
print(str.lengthOfBytes(using: .utf8))
// 2. 返回字符個(gè)數(shù)
print(str.characters.count)
// 3. 將字符串轉(zhuǎn)換成 NSString
let ocStr = str as NSString
print(ocStr.length)
字符串拼接
- 直接在 "" 中使用
\(變量名)
的方式可以快速拼接字符串
let str1 = "Hello"
let str2 = "World"
let i = 32
str = "\(i) 個(gè) " + str1 + " " + str2
我和我的小伙伴再也不要考慮
stringWithFormat
了 :D
- 可選項(xiàng)的拼接
- 如果變量是可選項(xiàng)医寿,拼接的結(jié)果中會(huì)有
Optional
- 為了應(yīng)對(duì)強(qiáng)行解包存在的風(fēng)險(xiǎn)栏赴,蘋果提供了
??
操作符 -
??
操作符用于檢測(cè)可選項(xiàng)是否為nil
- 如果不是
nil
,使用當(dāng)前值 - 如果是
nil
靖秩,使用后面的值替代
- 如果不是
- 如果變量是可選項(xiàng)医寿,拼接的結(jié)果中會(huì)有
let str1 = "Hello"
let str2 = "World"
let i: Int? = 32
str = "\(i ?? 0) 個(gè) " + str1 + " " + str2
- 格式化字符串
- 在實(shí)際開發(fā)中须眷,如果需要指定字符串格式竖瘾,可以使用
String(format:...)
的方式
- 在實(shí)際開發(fā)中须眷,如果需要指定字符串格式竖瘾,可以使用
let h = 8
let m = 23
let s = 9
let timeString = String(format: "%02d:%02d:%02d", arguments: [h, m, s])
let timeStr = String(format: "%02d:%02d:%02d", h, m, s)
2.String & Range 的結(jié)合
- 在 Swift 中,
String
和Range
連用時(shí)花颗,語法結(jié)構(gòu)比較復(fù)雜 - 如果不習(xí)慣 Swift 的語法捕传,可以將字符串轉(zhuǎn)換成
NSString
再處理
let helloString = "我們一起飛"
(helloString as NSString).substringWithRange(NSMakeRange(2, 3))
- 使用 Range<Index> 的寫法
3.0
let startIndex = helloString.index(str.startIndex, offsetBy: 2)
let endIndex = helloString.index(str.endIndex, offsetBy: -2)
helloString.substring(with: startIndex..<endIndex)
4.0
let startIndex = helloString.index(str.startIndex, offsetBy: 2)
let endIndex = helloString.index(str.endIndex, offsetBy: -2)
helloString[startIndex..<endIndex]
六.集合
1.數(shù)組
- 數(shù)組使用
[]
定義,這一點(diǎn)與 OC 相同
//: [Int]
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- 遍歷
// 1> 使用下標(biāo)遍歷
for i in 0..<numbers.count {
print(numbers[I])
}
print("---- 遍歷數(shù)組項(xiàng)")
// 2> 遍歷數(shù)組項(xiàng)
for e in numbers {
print(e)
}
print("---- 遍歷數(shù)組項(xiàng)和索引")
// 3> 遍歷數(shù)組項(xiàng)和索引
for e in numbers.enumerated() {
print("\(e.offset) \(e.element)")
}
print("---- 遍歷數(shù)組項(xiàng)和索引 2")
// 4> 遍歷數(shù)組項(xiàng)和索引 2
for (n, c) in numbers.enumerated() {
print("\(n) \(c)")
}
print("---- 倒序遍歷數(shù)組")
// 5> 倒序遍歷數(shù)組
for s in numbers.reversed() {
print(s)
}
print("---- 倒序遍歷數(shù)組內(nèi)容和下標(biāo)")
// 6> 倒序遍歷數(shù)組內(nèi)容和下標(biāo)
for (n, c) in numbers.enumerated().reversed() {
print("\(n) \(c)")
}
- 可變&不可變
-
let
定義不可變數(shù)組 -
var
定義可變數(shù)組
-
let array = ["zhangsan", "lisi"]
//: 不能向不可變數(shù)組中追加內(nèi)容
//array.append("wangwu")
var array1 = ["zhangsan", "lisi"]
//: 向可變數(shù)組中追加內(nèi)容
array1.append("wangwu")
- 數(shù)組的類型
- 如果初始化時(shí)扩劝,所有內(nèi)容類型一致庸论,擇數(shù)組中保存的是該類型的內(nèi)容
- 如果初始化時(shí),所有內(nèi)容類型不一致棒呛,擇數(shù)組中保存的是
NSObject
//: array1 僅允許追加 String 類型的值
//array1.append(18)
var array2 = ["zhangsan", 18] as [Any]
//: 在 Swift 中聂示,數(shù)字可以直接添加到集合,不需要再轉(zhuǎn)換成 `NSNumber`
array2.append(100)
- 數(shù)組的定義和實(shí)例化
- 使用
:
可以只定義數(shù)組的類型 - 實(shí)例化之前不允許添加值
- 使用
[類型]()
可以實(shí)例化一個(gè)空的數(shù)組
- 使用
var array3: [String]
//: 實(shí)例化之前不允許添加值
//array3.append("laowang")
//: 實(shí)例化一個(gè)空的數(shù)組
array3 = [String]()
array3.append("laowang")
- 數(shù)組的合并
- 必須是相同類型的數(shù)組才能夠合并
- 開發(fā)中条霜,通常數(shù)組中保存的對(duì)象類型都是一樣的催什!
array3 += array1
//: 必須是相同類型的數(shù)組才能夠合并涵亏,以下兩句代碼都是不允許的
//array3 += array2
//array2 += array3
- 數(shù)組的刪除
//: 刪除指定位置的元素
array3.removeAtIndex(3)
//: 清空數(shù)組
array3.removeAll()
- 內(nèi)存分配
- 如果向數(shù)組中追加元素宰睡,超過了容量,系統(tǒng)會(huì)增加合適的容量
var list = [Int]()
for i in 0...16 {
list.append(i)
print("添加 \(i) 容量 \(list.capacity)")
}
2.字典
- 定義
- 同樣使用
[]
定義字典 -
let
不可變字典 -
var
可變字典 -
[String : Any]
是最常用的字典類型
- 同樣使用
//: [String : Any] 是最常用的字典類型
var dict = ["name": "zhangsan", "age": 18]
- 賦值
- 賦值直接使用
dict[key] = value
格式 - 如果 key 不存在气筋,會(huì)設(shè)置新值
- 如果 key 存在拆内,會(huì)覆蓋現(xiàn)有值
- 賦值直接使用
//: * 如果 key 不存在,會(huì)設(shè)置新值
dict["title"] = "boss"
//: * 如果 key 存在宠默,會(huì)覆蓋現(xiàn)有值
dict["name"] = "lisi"
- 刪除一個(gè) KEY
// 刪除 key 如果不存在麸恍,什么也不會(huì)發(fā)生
dict.removeValue(forKey: "height")
print(dict)
// 另一種刪除方式
dict["title"] = nil
print(dict)
- 遍歷
-
k
,v
可以隨便寫 - 前面的是
key
- 后面的是
value
-
//: 遍歷
for (k, v) in dict {
print("\(k) ~~~ \(v)")
}
- 合并字典
- 如果 key 不存在搀矫,會(huì)建立新值抹沪,否則會(huì)覆蓋現(xiàn)有值
//: 合并字典
var dict1 = [String: Any]()
dict1["nickname"] = "大老虎"
dict1["age"] = 100
//: 如果 key 不存在,會(huì)建立新值瓤球,否則會(huì)覆蓋現(xiàn)有值
for (k, v) in dict1 {
dict[k] = v
}
print(dict)
七.錯(cuò)誤處理
反序列化JSON數(shù)據(jù)
- 網(wǎng)絡(luò)訪問代碼
/// Swift 4 中 字符串換行的寫法
let data = """
{
"weatherinfo": {
"city": "北京",
"cityid": "101010100",
"temp": "18",
"WD": "東南風(fēng)",
"WS": "1級(jí)",
"SD": "17%",
"WSE": "1",
"time": "17:05",
"isRadar": "1",
"Radar": "JC_RADAR_AZ9010_JB",
"njd": "暫無實(shí)況",
"qy": "1011",
"rain": "0"
}
}
""".data(using: String.Encoding.utf8)!
- JSON 反序列化
// 方式1:強(qiáng)try.加載失敗直接崩潰
let dict = try! JSONSerialization.jsonObject(with: data!, options: [])
print(dict)
// 方式2:可選try.反序列化失敗返回nil
let dict = try? JSONSerialization.jsonObject(with: data!, options: [])
print(dict)
// 方式3:默認(rèn)try.返回序列化失敗可以捕捉詳細(xì)信息
do {
let dict = try JSONSerialization.jsonObject(with: data!, options: [])
print(dict)
}catch {
print(error)
}