一、變數和常量 定義 let 定義常量,一經賦值不允許再修改 var 定義變數,賦值之後仍然可以修改 自動推導 Swift能夠根據右邊的代碼,推導出變數的準確類型 通常在開發時,不需要指定變數的類型 如果要指定變數,可以在變數名後使用:,然後跟上變數的類型 重要技巧:Option + Click 可 ...
一、變數和常量
定義
let
定義常量,一經賦值不允許再修改var
定義變數,賦值之後仍然可以修改
//: # 常量
//: 定義常量並且直接設置數值
let x = 20
//: 常量數值一經設置,不能修改,以下代碼會報錯
// x = 30
//: 使用 `: 類型`,僅僅只定義類型,而沒有設置數值
let x1: Int
//: 常量有一次設置數值的機會,以下代碼沒有問題,因為 x1 還沒有被設置數值
x1 = 30
//: 一旦設置了數值之後,則不能再次修改,以下代碼會報錯,因為 x1 已經被設置了數值
// x1 = 50
//: # 變數
//: 變數設置數值之後,可以繼續修改數值
var y = 200
y = 300
自動推導
- Swift能夠根據右邊的代碼,推導出變數的準確類型
- 通常在開發時,不需要指定變數的類型
- 如果要指定變數,可以在變數名後使用:,然後跟上變數的類型
重要技巧:Option + Click 可以查看變數的類型
沒有隱式轉換!!!
- Swift 對數據類型要求異常嚴格
- 任何時候,都不會做隱式轉換
如果要對不同類型的數據進行計算,必須要顯式的轉換
let x2 = 100
let y2 = 10.5
let num1 = Double(x2) + y2
let num2 = x2 + Int(y2)
let & var 的選擇
- 應該儘量先選擇常量,只有在必須修改時,才需要修改為
var
- 在 Xcode 7.0 中,如果沒有修改變數,Xcode 會提示修改為
let
二、Optional 可選類型
Optional
是 Swift 的一大特色,也是 Swift 初學者最容易困惑的問題- 定義變數時,如果指定是
可選的
,表示該變數可以有一個指定類型的值,也可以是 nil
- 定義變數時,在類型後面添加一個
?
,表示該變數是可選的 - 變數可選項的預設值是
nil
- 常量可選項沒有預設值,主要用於在構造函數中給常量設置初始數值
//: num 可以是一個整數,也可以是 nil,註意如果為 nil,不能參與計算
let num: Int? = 10
- 如果 Optional 值是
nil
,不允許參與計算 - 只有
解包(unwrap)
後才能參與計算 - 在變數後添加一個
!
,可以強行解包
註意:必須要確保解包後的值不是 nil,否則會報錯
//: num 可以是一個整數,也可以是 nil,註意如果為 nil,不能參與計算
let num: Int? = 10
//: 如果 num 為 nil,使用 `!` 強行解包會報錯
let r1 = num! + 100
//: 使用以下判斷,當 num 為 nil 時,if 分支中的代碼不會執行
if let n = num {
let r = n + 10
}
常見錯誤
unexpectedly found nil while unwrapping an Optional value
翻譯
在[解包]一個可選值時發現 nil
??
運算符
??
運算符可以用於判斷變數/常量
的數值是否是nil
,如果是則使用後面的值替代- 在使用 Swift 開發時,
??
能夠簡化代碼的編寫
let num: Int? = nil
let r1 = (num ?? 0) + 10
print(r1)
三、控制流
if
- Swift 中沒有 C 語言中的
非零即真
概念 - 在邏輯判斷時必須顯示地指明具體的判斷條件
true
/false
- if 語句條件的
()
可以省略 - 但是
{}
不能省略
let num = 200
if num < 10 {
print("比 10 小")
} else if num > 100 {
print("比 100 大")
} else {
print("10 ~ 100 之間的數字")
}
三目運算
- Swift 中的
三目
運算保持了和 OC 一致的風格
var a = 10
var b = 20
let c = a > b ? a : b
print(c)
適當地運用三目,能夠讓代碼寫得更加簡潔
可選類型判斷
- 由於可選類型的內容可能為
nil
,而一旦為nil
則不允許參與計算 - 因此在實際開發中,經常需要判斷可選類型的內容是否為
nil
單個可選類型判斷
let url = NSURL(string: "http://www.baidu.com")
//: 方法1: 強行解包 - 缺陷,如果 url 為空,運行時會崩潰
let request = NSURLRequest(URL: url!)
//: 方法2: 首先判斷 - 代碼中仍然需要使用 `!` 強行解包
if url != nil {
let request = NSURLRequest(URL: url!)
}
//: 方法3: 使用 `if let`,這種方式,表明一旦進入 if 分支,u 就不在是可選類型
if let u = url where u.host == "www.baidu.com" {
let request = NSURLRequest(URL: u)
}
可選類型條件判斷
//: 1> 初學 swift 一不小心就會讓 if 的嵌套層次很深,讓代碼變得很醜陋
if let u = url {
if u.host == "www.baidu.com" {
let request = NSURLRequest(URL: u)
}
}
//: 2> 使用 where 關鍵字,
if let u = url where u.host == "www.baidu.com" {
let request = NSURLRequest(URL: u)
}
- 小結
if let
不能與使用&&
、||
等條件判斷- 如果要增加條件,可以使用
where
子句 - 註意:
where
子句沒有智能提示
多個可選類型判斷
//: 3> 可以使用 `,` 同時判斷多個可選類型是否為空
let oName: String? = "張三"
let oNo: Int? = 100
if let name = oName {
if let no = oNo {
print("姓名:" + name + " 學號: " + String(no))
}
}
if let name = oName, let no = oNo {
print("姓名:" + name + " 學號: " + String(no))
}
判斷之後對變數需要修改
let oName: String? = "張三"
let oNum: Int? = 18
if var name = oName, num = oNum {
name = "李四"
num = 1
print(name, num)
}
guard
guard
是與if let
相反的語法,Swift 2.0 推出的
let oName: String? = "張三"
let oNum: Int? = 18
guard let name = oName else {
print("name 為空")
return
}
guard let num = oNum else {
print("num 為空")
return
}
// 代碼執行至此,name & num 都是有值的
print(name)
print(num)
- 在程式編寫時,條件檢測之後的代碼相對是比較複雜的
- 使用 guard 的好處
- 能夠判斷每一個值
- 在真正的代碼邏輯部分,省略了一層嵌套
switch
switch
不再局限於整數switch
可以針對任意數據類型
進行判斷- 不再需要
break
- 每一個
case
後面必須有可以執行的語句 - 要保證處理所有可能的情況,不然編譯器直接報錯,不處理的條件可以放在
default
分支中 - 每一個
case
中定義的變數僅在當前case
中有效,而 OC 中需要使用{}
let score = "優"
switch score {
case "優":
let name = "學生"
print(name + "80~100分")
case "良": print("70~80分")
case "中": print("60~70分")
case "差": print("不及格")
default: break
}
- switch 中同樣能夠賦值和使用
where
子句
let point = CGPoint(x: 10, y: 10)
switch point {
case let p where p.x == 0 && p.y == 0:
print("中心點")
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("對角線")
default:
print("其他")
}
- 如果只希望進行條件判斷,賦值部分可以省略
switch score {
case _ where score > 80: print("優")
case _ where score > 60: print("及格")
default: print("其他")
}
四、for 迴圈
- OC 風格的迴圈
var sum = 0
for var i = 0; i < 10; i++ {
sum += i
}
print(sum)
for-in
,0..<10 表示從0到9
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)
- 省略下標
_
能夠匹配任意類型_
表示忽略對應位置的值
for _ in 0...10 {
print("hello")
}
五、字元串
在 Swift 中絕大多數的情況下,推薦使用
String
類型
- String 是一個結構體,性能更高
- String 目前具有了絕大多數 NSString 的功能
- String 支持直接遍歷
- NSString 是一個 OC 對象,性能略差
- Swift 提供了
String
和NSString
之間的無縫轉換
字元串演練
- 遍歷字元串中的字元
for s in str.characters {
print(s)
}
- 字元串長度
// 返回以位元組為單位的字元串長度,一個中文占 3 個位元組
let len1 = str.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
// 返回實際字元的個數
let len2 = str.characters.count
// 返回 utf8 編碼長度
let len3 = str.utf8.count
- 字元串拼接
- 直接在 "" 中使用
\(變數名)
的方式可以快速拼接字元串
- 直接在 "" 中使用
let str1 = "Hello"
let str2 = "World"
let i = 32
str = "\(i) 個 " + str1 + " " + str2
我和我的小伙伴再也不要考慮
stringWithFormat
了 :D
- 可選項的拼接
- 如果變數是可選項,拼接的結果中會有
Optional
- 為了應對強行解包存在的風險,蘋果提供了
??
操作符 ??
操作符用於檢測可選項是否為nil
- 如果不是
nil
,使用當前值 - 如果是
nil
,使用後面的值替代
- 如果不是
- 如果變數是可選項,拼接的結果中會有
let str1 = "Hello"
let str2 = "World"
let i: Int? = 32
str = "\(i ?? 0) 個 " + str1 + " " + str2
- 格式化字元串
- 在實際開發中,如果需要指定字元串格式,可以使用
String(format:...)
的方式
- 在實際開發中,如果需要指定字元串格式,可以使用
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)
String & Range 的結合
- 在 Swift 中,
String
和Range
連用時,語法結構比較複雜 - 如果不習慣 Swift 的語法,可以將字元串轉換成
NSString
再處理
let helloString = "我們一起飛"
(helloString as NSString).substringWithRange(NSMakeRange(2, 3))
- 使用 Range 的寫法
let startIndex = helloString.startIndex.advancedBy(0)
let endIndex = helloString.endIndex.advancedBy(-1)
helloString.substringWithRange(startIndex..<endIndex)
六、集合
數組
- 數組使用
[]
定義,這一點與 OC 相同
//: [Int]
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- 遍歷
for num in numbers {
print(num)
}
- 通過下標獲取指定項內容
let num1 = numbers[0]
let num2 = numbers[1]
- 可變&不可變
let
定義不可變數組var
定義可變數組
let array = ["zhangsan", "lisi"]
//: 不能向不可變數組中追加內容
//array.append("wangwu")
var array1 = ["zhangsan", "lisi"]
//: 向可變數組中追加內容
array1.append("wangwu")
- 數組的類型
- 如果初始化時,所有內容類型一致,擇數組中保存的是該類型的內容
- 如果初始化時,所有內容類型不一致,擇數組中保存的是
NSObject
//: array1 僅允許追加 String 類型的值
//array1.append(18)
var array2 = ["zhangsan", 18]
//: 在 Swift 中,數字可以直接添加到集合,不需要再轉換成 `NSNumber`
array2.append(100)
//: 在 Swift 中,如果將結構體對象添加到集合,仍然需要轉換成 `NSValue`
array2.append(NSValue(CGPoint: CGPoint(x: 10, y: 10)))
- 數組的定義和實例化
- 使用
:
可以只定義數組的類型 - 實例化之前不允許添加值
- 使用
[類型]()
可以實例化一個空的數組
- 使用
var array3: [String]
//: 實例化之前不允許添加值
//array3.append("laowang")
//: 實例化一個空的數組
array3 = [String]()
array3.append("laowang")
- 數組的合併
- 必須是相同類型的數組才能夠合併
- 開發中,通常數組中保存的對象類型都是一樣的!
array3 += array1
//: 必須是相同類型的數組才能夠合併,以下兩句代碼都是不允許的
//array3 += array2
//array2 += array3
- 數組的刪除
//: 刪除指定位置的元素
array3.removeAtIndex(3)
//: 清空數組
array3.removeAll()
- 記憶體分配
- 如果向數組中追加元素,超過了容量,會直接在現有容量基礎上 * 2
var list = [Int]()
for i in 0...16 {
list.append(i)
print("添加 \(i) 容量 \(list.capacity)")
}
字典
- 定義
- 同樣使用
[]
定義字典 let
不可變字典var
可變字典[String : NSObject]
是最常用的字典類型
- 同樣使用
//: [String : NSObject] 是最常用的字典類型
var dict = ["name": "zhangsan", "age": 18]
- 賦值
- 賦值直接使用
dict[key] = value
格式 - 如果 key 不存在,會設置新值
- 如果 key 存在,會覆蓋現有值
- 賦值直接使用
//: * 如果 key 不存在,會設置新值
dict["title"] = "boss"
//: * 如果 key 存在,會覆蓋現有值
dict["name"] = "lisi"
dict
- 遍歷
k
,v
可以隨便寫- 前面的是
key
- 後面的是
value
//: 遍歷
for (k, v) in dict {
print("\(k) ~~~ \(v)")
}
- 合併字典
- 如果 key 不存在,會建立新值,否則會覆蓋現有值
//: 合併字典
var dict1 = [String: NSObject]()
dict1["nickname"] = "大老虎"
dict1["age"] = 100
//: 如果 key 不存在,會建立新值,否則會覆蓋現有值
for (k, v) in dict1 {
dict[k] = v
}
print(dict)