1. 基本數(shù)據(jù)類型
1.1 常量和變量
// 常量
let a = 10
// 變量
var b = 11.1
1.2 類型安全和類型推斷
let和var定義常量,編譯器可以根據(jù)具體的值,來推斷類型。swift 是強類型語言,編譯的時候如果賦值類型和聲明類型不一致會報錯。
1.3 基本類型
// 基本類型
let aInt: Int = 10
let aFloat: Float = 10.1
let aDouble: Double = 10.0
let aBool: Bool = true
let aString: String = "a"
let aWrapString:String = """
百日依山盡,
黃河入海流。
"""
let aChar: Character = "a"
swift 中一切皆對象,所以基本類型也是類類型,也需要構(gòu)造器轉(zhuǎn)換。
// 類型轉(zhuǎn)換: 一切皆對象,利用構(gòu)造器轉(zhuǎn)換
let aLong: Int64 = Int64(aFloat)
1.4 類型別名
/ 類型別名
typealias MyInt = Int
let myInt: MyInt = 10
1.5 元組
元組是swift中新類型,python中也有這個類型。
// 元組
let tuple = (1,"json","errMsg")
tuple.0
tuple.1
tuple.2
1.6 可選類型
可選類型:可能有值,可能沒有值。
其他類型:必須是有值的。
可選類型:沒有初始化,默認(rèn)值是nil。
其他類型:在使用前必須初始化。
1.6.1 普通可選類型和隱式解析可選類型
// 普通可選:類型?
let aString: String? = "普通可選類型"
// 普通可選獲取值,必須強制解析
let aStr = aString!
type(of: aStr) // -> String
// 隱式解析可選類型: 類型!
let bString: String! = "隱式解析可選類型"
// 隱式解析可選類型,在定義時就制定了非空值,所以可以直接取值。
let bStr = bString
type(of: bStr) // -> String
1.6.2 可選綁定
let someOptional: String? = "hell world"
if let constantName = someOptional {
// String
print(type(of: constantName))
print(constantName)
} else {
// 綁定失敗
}
1.6.3 可選鏈
在java OC等語言中,沒有可選類型,也沒有可選調(diào)用鏈。所以會有 if else 的各種嵌套。
if (person != null){
if (person.name != null){
print(person.name.length())
}
}
在swift中語言中,可選調(diào)用鏈,整個鏈條上的值都可能是可選類型,如果值是nil,則終止后面的調(diào)用直接返回nil。
class Person{
var mac: Mac?
init?(mac: Mac?){
guard let mac = mac else { return nil }
self.mac = mac
}
// swift中的下標(biāo)語法,使得獲取某些值更加便捷。
subscript(index: String) -> Int {
switch index {
case "count": return self.mac?.name.count ?? 0
default:
return 0
}
}
}
class Mac{
let name: String = "mac book pro"
}
let person = Person(mac: nil)
print(person?.mac?.name.count ?? 0)
print(person?["count"] ?? 0)
1.7 運算符
算術(shù)運算符:+ - * / %
比較運算符:== != > < >= <=
三元運算符:問題 ?答案1 : 答案2
邏輯運算符: ! && ||
區(qū)間運算符:
// a..<b(半開區(qū)間)
for i in 0..<5{
}
// a...b(閉區(qū)間)
for i in 0...5{
}
// 單側(cè)區(qū)間
let names = ["a","b","c"]
for name in names[...2]{
print(name)
}
for name in names[1...]{
print(name)
}
空合運算符: a ?? b // a != nil ? a! : b
1.8 斷言
斷言主要用于測試程序。
assert(布爾表達式,“斷言失敗的信息”)
let age = 3
assert(age < 0,"age > 0")
斷言和異常的區(qū)別:
- 斷言用在哪些你知道絕對不會發(fā)生的事情上,來捕捉程序員自己的錯誤。
- 異常捕捉用戶或者環(huán)境的錯誤。
1.9 宏定義
swift中沒有宏定義,OC中的宏定義會轉(zhuǎn)為swift中全局常量 。
2. 字符串
字符串是結(jié)構(gòu)體類型。
在swift中結(jié)構(gòu)體和枚舉類型都是值類型的。值類型的數(shù)據(jù)在傳參的時候是進行拷貝的。保證了數(shù)據(jù)安全性。
// 定義字符串
let aString = "hello"
let bString = """
百日依山盡,
黃河入海流。
"""
// 字符串拼接
var mutableString = "hello"
mutableString += "world"
mutableString.append(" han meimei")
// 字符串插值 \(表達式或者變量)
print("hello world \(type(of: mutableString))")
print("hello world \(mutableString + String(1))")
// 字符串長度
mutableString.count
// 大小寫轉(zhuǎn)化
mutableString.lowercased()
mutableString.uppercased()
// 前綴后綴
mutableString.hasPrefix("hello")
mutableString.hasSuffix("world")
// 是否相等
aString == bString
3. 集合類型
集合是泛型。
可變集合:將集合賦值給 var 型變量。
不可變集合:將集合賦值給 let 型變量。
注意:swift中的不可變集合和Java中不可變集合不一樣的。swift不可變集合是真的不可變。 Java中的不可變集合是引用地址不能變,但是集合可以添加刪除元素。
3.1 Array
// 簡單語法
var someInts = [Int]()
// 泛型數(shù)組語法
someInts = Array<Int>()
someInts.append(3)
// 空數(shù)組
someInts = []
// 重復(fù)數(shù)組
var threeDoubles = Array(repeating:0.0, count:3)
// 數(shù)組連接
var anotherThreeDoubles = Array(repeating:2.4,count:3)
var sixDoubles = threeDoubles + anotherThreeDoubles
// 字面常量
var shopping = [1,3,4,5]
// 是否為空
shopping.isEmpty
shopping[1]
shopping.insert(3,at:0)
shopping.removeLast()
// 變量數(shù)組
for item in shopping {
print(item)
}
for (index, value) in shopping.enumerated() {
print("item \(String(index + 1)) : \(value)")
}
3.2 Set
一個類型存在Set中,該類型必須是可哈希化的。相等的對象 hashValue 必須相同。、
a == b
a.hashValue == b.hashValue
所有的基本類型默認(rèn)都是可哈希化的。因此可以作為Set的類型或者字典鍵的類型。
可哈?;念愋?,必須遵循Hashable 協(xié)議,實現(xiàn) == 方法 和 hashValue值的放回。
// 定義Set
var letters = Set<String>()
var set: Set<String> = []
// 插入值
letters.insert("a")
// 清空元素
letters = []
// 字面量創(chuàng)建集合
var favorite: Set<String> = ["hello", "world"]
// 刪除
favorite.remove("hello")
// 判斷是否包含元素
favorite.contains("hello")
// 遍歷集合
var set: Set<String> = ["我","是","最","棒","的"]
for item in set{
if item == "是" {
set.remove(item)
}
}
注意:swift中的集合是可以遍歷刪除,Java中的集合如果遍歷刪除會出發(fā)fast-fail, 所以Java的變臉刪除一般都是迭代器刪除。
3.3 Dictionary
swift 的字典使用 Dictionary<Key, Value> 定義,其中 Key 是一種可以在字典中被用作鍵的類型,Value 是字典中對應(yīng)于這些鍵所存儲值的數(shù)據(jù)類型。
一個字典的
Key類型必須遵循Hashable協(xié)議,就像Set的值類型。
你也可以用 [Key: Value] 這樣簡化的形式去表示字典類型。雖然這兩種形式功能上相同,但是后者是首選,
// 定義一個字典
var nameOfIntergers = [Int: String]()
// 空字典
nameOfIntergers = [:]
// 字面量
var nameOfInt = [1:"hello",2:"world"]
// 刪除
nameOfInt.removeValue(forKey:1)
4. 流程控制
4.1 for-in
var set: Set<String> = ["我","是","最","棒","的"]
// 遍歷Array和set
for name in set {
print(name)
}
// 遍歷dictionary
var dic = [1:"hello",2:"world"]
for (key,value) in dic {
print("key = \(key), value = \(value)")
}
// 遍歷區(qū)間
for i in 0..<set.count{
print(i)
}
print("\n \n")
// 指定步長,遍歷開區(qū)間
for tickMark in stride(from: 0, to: 60, by: 5){
print(tickMark)
}
// j指定步長,遍歷閉區(qū)間
for tickMark in stride(from: 0, through: 60, by: 5){
print(tickMark)
}
4.2 while
while 條件{
表達式
}
repeat{
} while 條件
while 和 repeat while 的循環(huán)次數(shù)是一樣的。
swift 沒有 i++。 賦值表達式?jīng)]有返回值。
4.3 if
if 條件{
// 表達式1
} else if 條件1 {
} else {
}
4.4 guard
- 與if語句相同的是,guard也是基于一個表達式的布爾值去判斷一段代碼是否該被執(zhí)行。
- 與if語句不同的是,guard只有在條件不滿足的時候才會執(zhí)行這段代碼。
class Person{
var mac: Mac?
init?(mac: Mac?){
// mac == nil 時直接返回nil
guard let mac = mac else { return nil }
// mac != nil 才走下面的邏輯
self.mac = mac
}
}
4.4 switch
swift中的switch 更強大,進行模式匹配。
字符串匹配
let a = "a"
switch "b" {
case "a":
print("a")
case "b":
print("b")
default:
print("默認(rèn)值")
}
區(qū)間匹配
let cout = 32
switch cout {
case 1...3:
print("in 1...3")
case 30...40:
print("in 30...40")
default:
print("默認(rèn)匹配")
}
元組
let somePoint = (1,20)
switch somePoint {
case (0,0):
print("(0,0)")
case (1,_):
print("first = 1,second 隨意")
case (_,20):
print("first 隨意,second = 20")
default:
print("沒有匹配上")
}
值綁定
let anotherPoint = (2,0)
switch anotherPoint {
case (let x,0):
print("x = \(x), y = 0")
case (2, let y):
print("x = 2, y = \(y)")
case (let x ,let y):
print("x = \(x),y = \(y)")
}
where 附加條件
let yetAnotherPoint = (1,-1)
switch yetAnotherPoint {
case let (x,y) where x == y:
print("x = \(x),y = \(y)")
case let (x, y) where x == -y:
print("x = \(x),y = \(y)")
default:
print("x = \(yetAnotherPoint.0),y = \(yetAnotherPoint.1)")
}
符合型
let char = "a"
switch char {
case "a", "e", "i", "o", "u":
print(char)
default:
print("其他char")
}
穿透
var index = 10
switch index {
case 10:
index += 1
fallthrough
default:
index += 1
}
// 12 穿透執(zhí)行
print(index)
4.5 控制轉(zhuǎn)移
·continue break
5. 函數(shù)
5.1 函數(shù)的定義
func 函數(shù)名(參數(shù)名:類型,參數(shù)名:類型)-> 返回類型{
// 執(zhí)行體
}
func minMax(array: [Int]) -> (min:Int,max:Int){
var currentMin = array[0]
var currentMax = array[0]
for value in array {
if value > currentMax {
currentMax = value
} else if value < currentMin{
currentMin = value
}
}
return (currentMin,currentMax)
}
let array = [1,3,4,5,6,7,8]
print("min = \(minMax(array: array).min) max = \(minMax(array:array).max)")
5.2 隱式返回函數(shù)
如果函數(shù)體是一個單行return 語句,那么這個return可以省略掉。
func greeting(person: String) -> String {
"hello," + person + "!"
}
5.3 參數(shù)標(biāo)簽和參數(shù)名稱
參數(shù)標(biāo)簽使代碼有更強的可讀性。
- 在參數(shù)名稱前面指定參數(shù)標(biāo)簽。
- 如果沒有指定參數(shù)標(biāo)簽,參數(shù)名稱也就是參數(shù)標(biāo)簽。
- 下劃線 _ 放到參數(shù)名稱前面,可以省略掉參數(shù)標(biāo)簽,一般不這么用。
func someFuncation(argumentLabel parameterName: Int) -> Int {
// parameterName 參數(shù)名稱, argumentLabel 標(biāo)簽參數(shù)
}
// from 是參數(shù)標(biāo)簽,hometown是參數(shù)名稱
func greet(person:String,from hometown: String){
print(person+" from "+hometown)
}
greet(person: "wangbo", from: "haidian")
5.4 默認(rèn)參數(shù)值
指定默認(rèn)參數(shù)值,也是實現(xiàn)函數(shù)重載的方式。
func someFuncation(param: Int, param1: Int = 2){
}
// 調(diào)用
someFuncation(param: 3)
someFuncation(param: 3, param1: 3)
5.5 可變參數(shù)
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
5.6 輸入輸出參數(shù)
函數(shù)的參數(shù)默認(rèn)是常量,不能修改的。如果想要修改參數(shù)的值,就要把參數(shù)定義為輸入輸出參數(shù)(參數(shù)類型前 inout) 。并且傳入的參數(shù)是個變量。
var ar = [Int]()
// 參數(shù)類型前加 inout 表示是輸入輸出參數(shù),可以修改
func add(array: inout [Int]) -> [Int] {
for i in 1...5{
array.append(i)
}
return array
}
// 調(diào)用的時候?qū)崊⑶懊婕?&,表示這個參數(shù)可以被修改
for item in add(array: &ar) {
print(item)
}
5.7 函數(shù)類型
func funcation(param: Int, param1: String) -> [Int]{
}
// 函數(shù)的類型
(Int,String) -> [Int]
swift 中函數(shù)式一等公民,函數(shù)類型像其他類型一樣可以定義變量, 也可以作為函數(shù)返回類型。
typealias FuncationType = (Int,Int) -> Int
func some(funcation: FuncationType) -> Int{
let a = 10, b = 100
return funcation(a,b)
}
let sum = some { (a, b) -> Int in
return a + b
}
5.8 嵌套函數(shù)
函數(shù)內(nèi)定義函數(shù)。
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
6. 閉包
swift的閉包和OC中block,Java中Lambda一樣都是用于模塊之間通訊的。
- 閉包可以捕獲上下文中的變量。
- 閉包就是一個匿名的函數(shù)體。
- Java 中的lambda就是一個匿名內(nèi)部類。
6.1 閉包表達式語法
{(parameters) -> returnType in
執(zhí)行體
}
例子
var names = ["a","dsf","weea","3psd"]
names.sort(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
for item in names {
print(item)
}
swift 的表達式擁有更簡潔的風(fēng)格。
- 利用上下文推斷參數(shù)和返回值類型
- 隱式返回單表達式閉包,單表達式閉包可以省略return關(guān)鍵字。
- 參數(shù)名稱縮寫。
- 尾隨閉包語法。
根據(jù)上下文推斷類型
因為閉包是作為函數(shù)的參數(shù)傳入的,可以根據(jù)參數(shù)的類型來推斷閉包的類型,所以閉包的 參數(shù)類型 和 返回類型 都可以省略。
names.sort(by: { s1, s2 in return s1 < s2 })
單表達式隱式返回
names.sort(by: { s1,s2 in s1 > s2 })
參數(shù)名縮寫
names.sort(by:{ $0 > $1})
運算符方法
names.sort(by: > )
6.2 尾隨閉包
如果將閉包表達式作為最后一個參數(shù)傳遞給函數(shù),將這個閉包替換成尾隨閉包的形式。
尾隨閉包不用寫參數(shù)標(biāo)簽。
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函數(shù)體部分
}
// 以下是不使用尾隨閉包進行函數(shù)調(diào)用
someFunctionThatTakesAClosure(closure: {
// 閉包主體部分
})
// 以下是使用尾隨閉包進行函數(shù)調(diào)用
someFunctionThatTakesAClosure() {
// 閉包主體部分
}
6.3 值捕獲
- 閉包可以捕獲上下文中的常量或變量。
- 閉包就是函數(shù)內(nèi)部與函數(shù)外部連接的橋梁。
閉包的用途:
- 讀取函數(shù)內(nèi)部的變量。
- 讓這些變量的值始終在內(nèi)存中。
func f1(amount: Int) -> () -> Int{
var total = 10
func f2() -> Int{
total += amount
return total
}
return f2
}
let res = f1(amount: 5)
print(res()) // 15
print(res()) // 20
let res1 = f2(amount: 5)
print(res()) // 15
f1 是 f2的父函數(shù),f2賦值給一個全局變量,f2一直在內(nèi)存中,f2依賴于f1,因此f1也始終在內(nèi)存中,不會在調(diào)用結(jié)束后,被垃圾回收機制回收。
閉包是引用類型,一個對象屬性賦值給一個閉包,如果閉包直接訪問了該對象或該對象的成員,就會引起循環(huán)引用。
6.4 逃逸閉包
閉包作為函數(shù)的參數(shù),分為逃逸閉包和非逃逸閉包。默認(rèn)是非逃逸閉包。逃逸閉包在閉包類型前面加上 @escaping 。
- 逃逸閉包的比函數(shù)體要晚執(zhí)行(比如異步回調(diào)執(zhí)行閉包)。
- 非逃逸閉包和函數(shù)提一起執(zhí)行。
// 逃逸閉包
func sun(callBack: @escaping (String) -> Void){
DispatchQueue
.global()
.asyncAfter(deadline: DispatchTime.init(uptimeNanoseconds: 1000)) {
callBack("我逃出sun的生命周期")
}
print("sun 執(zhí)行完畢")
}
sun { print($0) }
// 非逃逸閉包
func moon(callBack: (String) -> Void){
print("moon 執(zhí)行")
callBack("我沒有逃出moon的生命周期")
}
moon { print($0) }
6.5 自動閉包
var count = 10
let f = { count += 10 }
print(count)
f()
print(count)
7. 類
7.1 屬性
7.1.1 存儲屬性
- 可以是 let var
- 要么默認(rèn)初始化,要么init構(gòu)造器初始化
- 可選類型的存儲屬性,沒有在構(gòu)造器初始化,會有默認(rèn)初始化 nil
- 結(jié)構(gòu)體和枚舉賦值給常量,它的變量存儲屬性也不能修改。
class Person{
let id: Int
var name: String = "wangbo"
// var bb: String
// 如果沒有默認(rèn)初始化,就必須在init中初始化
// 延遲加載存儲屬性,第一次調(diào)用時才初始值,延遲屬性必須是var
lazy var array = Array(repeating: 0, count: 3)
init(id: Int) {
self.id = id
}
}
// 存儲屬性也是可以直接修改和取值的
let person = Person(id: 10)
person.name = "hh"
person.array = Array(repeating: 10, count: 3)
print(person.name)
- 全局變量和局部變量都是存儲型變量。
- 全局變量都是延遲計算的,跟延遲存儲屬性類似,但是不用 lazy 標(biāo)志。
7.1.2 計算屬性
計算屬性提供一個 getter 和一個可選的 setter方法。來間接獲取或設(shè)置屬性值。
計算屬性其實就是 java 里的 getter 和 setter 方法
class Person{
var age: Int{
get{
return self.age
}
set{
self.age = newValue
}
}
}
let person = Person()
person.age = 10
print(person.age)
只讀計算屬性
class Person{
// 只讀計算屬性,省略掉 get{ return 10 }
var age : Int{
return 10
}
}
let person = Person()
print(person.age)
7.1.3 屬性觀察器
屬性觀察器一般為存儲屬性提供的,計算屬性可以,但是沒必要,在setter方法中就可以監(jiān)聽變化。
class Person{
var name = "hh" {
willSet{
print("name = \(self.name) 將變?yōu)?\(newValue)")
}
didSet{
print("舊的值是 \(oldValue) 當(dāng)前值\(self.name)")
}
}
}
let person = Person()
person.name = "www"
7.1.4 類型屬性
- static修飾的屬性就是類型屬性
class Person{
static let a: String = "hello"
}
Person.a
7.2 方法
7.2.1 普通方法
結(jié)構(gòu)體,枚舉,類都可以有方法。
特殊點:swift的類方法,可以用static修飾,也可以用class修飾。
區(qū)別:
- static 修飾的類型方法不能被復(fù)寫。
- class 修飾的類方法可以被子類復(fù)寫。
class Person{
static let a: String = "hello"
// 實例方法
func work(at where: String) -> Void {
print("at \(`where`)" world)
}
// 不可以被復(fù)寫的類方法
static func sayHello(){
print("hello")
}
// 可以被子類復(fù)寫的類方法
class func sayWorld(){
print("world")
}
}
class Teacher: Person{
override class func sayWorld() {
print("teacher say world")
}
}
7.2.2 構(gòu)造器
構(gòu)造器沒有返回值。
swift 的類,如果存儲屬性沒有指定默認(rèn)值,就必須要有構(gòu)造器。
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
7.2.3 指定構(gòu)造器和便利構(gòu)造器
- 一個類必須有一個指定構(gòu)造器
- 便利構(gòu)造器必須依賴于指定構(gòu)造器
class Person{
let a: Int
var b: String
// 指定構(gòu)造器
init(a: Int, b:String) {
self.a = a
self.b = b
}
// 便利構(gòu)造器
convenience init(a: Int) {
self.init(a: a, b:"haha")
}
}
let pe = Person(a: 10)
let p2 = Person(a: 12,b:"world")
7.2.4 可失敗構(gòu)造器
可失敗構(gòu)造器一般用于結(jié)構(gòu)體,表示model層數(shù)據(jù)可能失敗。
構(gòu)造器通過返回一個 nil 表示這是個可失敗構(gòu)造器。
struct Person{
let name: String
init?(name: String){
if name.isEmpty {
return nil
}
self.name = name
}
}
let person = Person(name: "")
// Optional<Person>
print(type(of: person))
7.2.5 必要構(gòu)造器
class SomeClass {
required init() {
// 表明子類必須實現(xiàn)該構(gòu)造器
}
}
7.3 析構(gòu)器
deinit(){
// 釋放資源
}
7.3 繼承
swift的類如果不指定父類,是沒有父類的。不像其他語言默認(rèn)繼承 Object類。
子類可以繼承父類的屬性,方法,并重寫父類的屬性和方法。
- 方法前加 final 修飾符,這個方法不能被重寫。
- 類前加 final 修飾符,這個類不能被繼承。
7.4 類型轉(zhuǎn)換
7.4.1 判斷類型 is
class Person{
let name: String
init(name: String) {
self.name = name
}
}
class Teacher: Person{
var age: Int
init(name: String,age: Int) {
self.age = age
super.init(name: name)
}
}
let teacher = Teacher(name: "hh", age: 29)
if teacher is Person {
print("teacher 是Person的子類")
}
7.4.2 類型轉(zhuǎn)換 as? as!
let teacher = Teacher(name: "hh", age: 29)
guard let tea = (teacher as? Person) else{
print("轉(zhuǎn)換失敗")
}
print("轉(zhuǎn)換成功")
as? 表示可能轉(zhuǎn)換失敗,返回nil。as! 表示一定能轉(zhuǎn)換成功。
7.5 擴展
擴展可以在不訪問一個類,結(jié)構(gòu)體,枚舉,源代碼的基礎(chǔ)上,給類,結(jié)構(gòu)體,枚舉添加一些屬性,方法,實現(xiàn)協(xié)議等。替代之前的工具類。
- 添加計算型實例屬性和計算型類屬性
- 定義實例方法和類方法
- 提供新的構(gòu)造器
- 定義下標(biāo)
- 定義和使用新的嵌套類型
- 使已經(jīng)存在的類型遵循(conform)一個協(xié)議
extension SomeType {
// 在這里給 SomeType 添加新的功能
}
在項目中,擴展經(jīng)常用來格式化代碼和實現(xiàn)工具類。
7.5.1 擴展屬性
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
7.5.2 擴展構(gòu)造器
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()
}
extension Rect {
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)
}
}
7.5.3 擴展方法
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
mutating func square() {
self = self * self
}
}
7.5.4 擴展下標(biāo)
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
7.5.5 嵌套類型
extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0:
return .positive
default:
return .negative
}
}
}
7.6 嵌套類
swift中的嵌套類型,跟Java中的靜態(tài)內(nèi)部類一樣。
class Person{
var age: Int = 0
class Kind{
var name: String?
init?(name: String?) {
guard let name = name else { return nil }
self.name = name
}
}
}
let kind = Person.Kind(name: nil)
print(kind?.name ?? "")
7.7 訪問控制
open > public > interal > fileprivate > private
open: 包以外的類可以訪問,也可以繼承,override方法。
public:包以外的類可以訪問,但是不能繼承,override方法。
internal: 包訪問級別。相當(dāng)于package。默認(rèn)可寫可不寫。
fileprivate: 訪問級別所修飾的屬性或者方法在當(dāng)前的 Swift 源文件里可以訪問。
private:只有同一個類中的方法屬性才能訪問。
8. 結(jié)構(gòu)體
類和結(jié)構(gòu)的相同點:
- 都有存儲屬性和計算屬性
- 都可以定義方法
- 定義下表操作
- 定義構(gòu)造器
- 通過擴展以增加默認(rèn)實現(xiàn)之外的功能
- 遵循協(xié)議
類和結(jié)構(gòu)的不同點:
- 類是引用類型,結(jié)構(gòu)體是值類型
- 結(jié)構(gòu)體不允許繼承,就像final class一樣,是個常量類。
- 結(jié)構(gòu)體可以不定義構(gòu)造器,默認(rèn)會有一個按照屬性次序定義的構(gòu)造器。
- swift中除了class是引用類型,之外的都是值類型。
- 值類型賦值給 let 常量之后,即使屬性是可變屬性也可以修改。
- 引用類型賦值給 let 常量之后,可變屬性還是可以修改的。
- 值類型的比較 == != 相等。
- 引用類型的比較 === !== 相同。
struct PersonInfo{
let name: String
var age: Int
func say(word: String) -> Void {
print(word)
}
mutating func add() -> Int {
age = age + 1
return age
}
}
let person = PersonInfo(name: "haha", age: 10)
結(jié)構(gòu)體的普通方法是不能修改屬性的,只能在構(gòu)造器中修改屬性值。如果強行修改,只需在方法前加上 mutating 修飾符。
結(jié)構(gòu)體如果沒有定義構(gòu)造器,會有一個默認(rèn)的逐一成員構(gòu)造器。
9. 枚舉
9.1 枚舉語法
enum {
case north
case south
case east
case west
}
9.2 枚舉成員的集合
enum Beverage: CaseIterable {
case coffee,tea,juice
}
for item in Beverage.allCases{
print(item)
}
9.3 原始值
枚舉成員在定義時可以被默認(rèn)值他填充。填充的值就是原始值,原始值的類型就是枚舉繼承的類型。
enum Type: String{
case ALL = "all"
case NORMAL = "normal"
}
9.4 原始值隱式賦值
// Int 是原始值類型,隱式原始值是遞增的
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
// String 是原始值類型,隱式原始值為成員名
enum CompassPoint: String {
case north, south, east, west
}
// rawValue屬性可以訪問枚舉成員的原始值
print(Planet.venus.rawValue) // 輸出2
print(CompassPoint.north.rawValue) // 輸出north
// 使用原始值初始化枚舉值
let planet = Planet(rawValue: 3) // Planet.earth
9.5 枚舉值的關(guān)聯(lián)值
感覺用的不多
// 枚舉值的關(guān)聯(lián)值
enum BarCode{
case upc(Int, Int,Int,Int)
case qrCode(String)
}
let productCode = BarCode.upc(1, 23, 39, 219)
let productCode1 = BarCode.upc(3, 8, 9, 78)
switch productCode {
case let .upc(x,y,z,q):
print("x= \(x), y = \(y) ,z = \(z) ,q = \(q)")
default:
print("默認(rèn)值")
}
10. 協(xié)議
10.1 屬性
協(xié)議里可以有屬性,遵循這個協(xié)議的類結(jié)構(gòu)體枚舉都必須要有這個屬性。
- 必須是
var - 類型后面要有
{get set}{get}
protocol SomeProtocol{
var name: String {get set}
static var here: String { get }
}
class Person: SomeProtocol{
var name: String
static var here: String = "person"
init(name: String) {
self.name = name
}
}
let person = Person(name: "hh")
print(person.name)
person.name = "ww"
print(Person.here)
10.2 方法
protocol SomeProtocol{
// 值類型修改屬性的方法必須是 mutating修飾
mutating func changeName() -> String
}
class Person: SomeProtocol{
func changeName() -> String {
return "hehe"
}
}
struct Man: SomeProtocol{
var name: String
mutating func changeName() -> String {
name = "hhh"
return name
}
}
10.3 協(xié)議合成
協(xié)議組合使用 SomeProtocol & AnotherProtocol 的形式。你可以列舉任意數(shù)量的協(xié)議,用和符號(&)分開。
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
10.4 協(xié)議擴展
協(xié)議可以通過擴展來為遵循協(xié)議的類型提供屬性、方法以及下標(biāo)的實現(xiàn)。
- 計算屬性提供默認(rèn)實現(xiàn)
- 方法提供默認(rèn)實現(xiàn)
- extension Protocol where Self: 類 限定了協(xié)議Protocol的擴展實現(xiàn),只能由類的對象調(diào)用
protocol SomeProtocol{
// 普通方法
func add(age: Int) -> Int
// 屬性
var age: Int{get set}
// 構(gòu)造器
init(age: Int)
}
// 協(xié)議擴展
extension SomeProtocol{
// 實現(xiàn)計算屬性
var name: String {
return "hhh"
}
// 實現(xiàn)方法
func work(here: String) -> String {
return "我在 \(here) 工作"
}
}
// 協(xié)議擴展實現(xiàn)的限定,只能由Person對象調(diào)用
extension SomeProtocol where self: Person{
func sleep(time: String){
print("睡覺)
}
}
class Person: SomeProtocol{
func add(age: Int) -> Int {
self.age = self.age + age
return self.age
}
var age: Int
required init(age: Int) {
self.age = age
}
}
let person = Person(age: 10)
person.add(age: 10)
person.work(here: "北京")
11. 泛型
11.1 類結(jié)構(gòu)體泛型
struct Stack<T>{
var items:[T] = [T]()
var count: Int{
return items.count
}
mutating func push(item: T) {
items.append(item)
}
mutating func push(items: [T]){
for item in items {
self.items.append(item)
}
}
mutating func pop() -> T? {
return items.popLast() ?? nil
}
}
var stack = Stack<Int>()
stack.push(item: 1)
stack.push(items:[2,3,4,5])
stack.count
11.2 typealias 支持泛型
typealias StringDictionary<T> = Dictionary<String, T>
typealias DictionaryOfStrings<T : Hashable> = Dictionary<T, String>
typealias IntFunction<T> = (T) -> Int
typealias Vec3<T> = (T, T, T)
11.3 協(xié)議泛型
protocol SomeProtocol {
associatedtype T
}
12. 異常處理
在 Swift 中,錯誤用遵循 Error 協(xié)議的類型的值來表示。這個空協(xié)議表明該類型可以用于錯誤處理。
12.1 錯誤的定義
錯誤實現(xiàn)Error協(xié)議的類。一般用枚舉值表示。
enum VendingMachineError: Error {
case invalidSelection //選擇無效
case insufficientFunds(coinsNeeded: Int) //金額不足
case outOfStock //缺貨
}
12.2 錯誤處理
12.2.1 do-catch
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
} catch {
statements
}
catch 之后是模式匹配。
12.2.2 try?
func someThrowingFunction() throws -> Int {
// ...
}
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
// x 是個可選類型,效果和上面一樣,try?是個簡潔的語法
let x = try? someThrowingFunction()
12.2.3 try!
禁止錯誤的傳遞。try!認(rèn)為后面的表達式不會拋出錯誤。
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
12.2.4 throw
錯誤的傳遞
func canThrowErrors() throws -> String
func canThrowErrors() throws
13.內(nèi)存管理
swift 和 OC都是引用計數(shù)管理內(nèi)存,當(dāng)一個對象的引用計數(shù) = 0 時,就會被立即回收內(nèi)存。
JAVA語言是垃圾回收器,只有內(nèi)存壓力觸發(fā)垃圾回收器回收時,才會清理內(nèi)存。
所以,swift的內(nèi)存利用率更高。JAVA內(nèi)存利用低容易觸發(fā)OOM。
13.1 弱引用
弱引用是個可選類型,引用對象可以是個nil。不會持有的對象保存強引用。
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
13.2 無主引用
無主引用不是可選類型,必須有一個值。也不會對持有的對象強引用。
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
13.3 閉包引起的循環(huán)引用
獲列表中的每一項都由一對元素組成,一個元素是 weak 或 unowned 關(guān)鍵字,另一個元素是類實例的引用(例如 self)或初始化過的變量(如 delegate = self.delegate)
lazy var someClosure = {
// 捕獲列表
[unowned self, weak delegate = self.delegate]
(success, errorCode, errorMsg)
in
// 這里是閉包的函數(shù)體
}