swift 5.1語法 1小時(shí)入門

1. 基本數(shù)據(jù)類型

1.1 常量和變量

// 常量
let a = 10

// 變量
var b = 11.1

1.2 類型安全和類型推斷

  • letvar 定義常量轩娶,編譯器可以根據(jù)具體的值,來推斷類型坎怪。

  • swift 是強(qiáng)類型語言罢坝,編譯的時(shí)候如果賦值類型和聲明類型不一致會(huì)報(bào)錯(cuò)廓握。

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 中一切皆對(duì)象隙券,所以基本類型也是類類型男应,也需要構(gòu)造器轉(zhuǎn)換。

// 類型轉(zhuǎn)換: 一切皆對(duì)象娱仔,利用構(gòu)造器轉(zhuǎn)換
let aLong: Int64 = Int64(aFloat)

1.4 類型別名

/ 類型別名
typealias MyInt = Int
let myInt: MyInt = 10

1.5 元組

元組是swift中新類型沐飘,python中也有這個(gè)類型。

// 元組
let tuple = (1,"json","errMsg")
tuple.0
tuple.1
tuple.2

1.6 可選類型

可選類型:可能有值,可能沒有值耐朴。

其他類型:必須是有值的借卧。

可選類型:沒有初始化,默認(rèn)值是nil筛峭。

其他類型:在使用前必須初始化铐刘。

1.6.1 普通可選類型和隱式解析可選類型

// 普通可選:類型?
let aString: String? = "普通可選類型"
// 普通可選獲取值影晓,必須強(qiáng)制解析
let aStr = aString!
type(of: aStr)  // -> String


// 隱式解析可選類型: 類型!
let bString: String! = "隱式解析可選類型"
// 隱式解析可選類型镰吵,在定義時(shí)就制定了非空值,所以可以直接取值挂签。
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)用鏈饵婆。所以會(huì)有 if else 的各種嵌套勺馆。

if (person != null){
    if (person.name != null){
      print(person.name.length())
    }
}

在swift中語言中,可選調(diào)用鏈侨核,整個(gè)鏈條上的值都可能是可選類型谓传,如果值是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 運(yùn)算符

算術(shù)運(yùn)算符:+ - * / % 

比較運(yùn)算符:== !=  >  <  >=  <=

三元運(yùn)算符:?jiǎn)栴} 侥衬?答案1 : 答案2

邏輯運(yùn)算符: ! && ||

區(qū)間運(yùn)算符:
// 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)
}

空合運(yùn)算符: a ?? b   // a != nil ? a! : b

1.8 斷言

斷言主要用于測(cè)試程序诗祸。

assert(布爾表達(dá)式,“斷言失敗的信息”)

let age = 3
assert(age < 0,"age > 0")

斷言和異常的區(qū)別:

  • 斷言用在哪些你知道絕對(duì)不會(huì)發(fā)生的事情上轴总,來捕捉程序員自己的錯(cuò)誤直颅。
  • 異常捕捉用戶或者環(huán)境的錯(cuò)誤。

1.9 宏定義

swift中沒有宏定義怀樟,OC中的宏定義會(huì)轉(zhuǎn)為swift中全局常量 功偿。

2. 字符串

字符串是結(jié)構(gòu)體類型。

在swift中結(jié)構(gòu)體和枚舉類型都是值類型的往堡。值類型的數(shù)據(jù)在傳參的時(shí)候是進(jìn)行拷貝的械荷。保證了數(shù)據(jù)安全性。

// 定義字符串
let aString = "hello"
let bString = """
    百日依山盡虑灰,
    黃河入海流吨瞎。
"""

// 字符串拼接
var mutableString = "hello"
mutableString += "world"
mutableString.append(" han meimei")


// 字符串插值 \(表達(dá)式或者變量)
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

// 簡(jiǎn)單語法
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

一個(gè)類型存在Set中,該類型必須是可哈闲目化的洲脂。相等的對(duì)象 hashValue 必須相同。剧包、

a == b

a.hashValue == b.hashValue

所有的基本類型默認(rèn)都是可哈峡纸酰化的。因此可以作為Set的類型或者字典鍵的類型疆液。

可哈弦磺Γ化的類型,必須遵循Hashable 協(xié)議堕油,實(shí)現(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中的集合如果遍歷刪除會(huì)出發(fā)fast-fail, 所以Java的變臉刪除一般都是迭代器刪除掉缺。

3.3 Dictionary

swift 的字典使用 Dictionary<Key, Value> 定義卜录,其中 Key 是一種可以在字典中被用作鍵的類型,Value 是字典中對(duì)應(yīng)于這些鍵所存儲(chǔ)值的數(shù)據(jù)類型眶明。

一個(gè)字典的 Key 類型必須遵循 Hashable 協(xié)議艰毒,就像 Set 的值類型。

你也可以用 [Key: Value] 這樣簡(jiǎn)化的形式去表示字典類型搜囱。雖然這兩種形式功能上相同丑瞧,但是后者是首選,

// 定義一個(gè)字典
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 條件{
   表達(dá)式
}

repeat{
  
} while 條件

while 和 repeat while 的循環(huán)次數(shù)是一樣的。

swift 沒有 i++扮宠。 賦值表達(dá)式?jīng)]有返回值西乖。

4.3 if

if 條件{
  // 表達(dá)式1
} else if 條件1 {
  
} else {
  
}

4.4 guard

  • 與if語句相同的是,guard也是基于一個(gè)表達(dá)式的布爾值去判斷一段代碼是否該被執(zhí)行坛增。
  • 與if語句不同的是获雕,guard只有在條件不滿足的時(shí)候才會(huì)執(zhí)行這段代碼。
class Person{
    var mac: Mac?
    init?(mac: Mac?){
        // mac == nil 時(shí)直接返回nil
        guard let mac = mac else { return nil }
        // mac != nil 才走下面的邏輯
        self.mac = mac
    }
}

4.4 switch

swift中的switch 更強(qiáng)大轿偎,進(jìn)行模式匹配典鸡。

字符串匹配

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ù)體是一個(gè)單行return 語句,那么這個(gè)return可以省略掉。

func greeting(person: String) -> String {
  "hello," + person + "!"
}

5.3 參數(shù)標(biāo)簽和參數(shù)名稱

參數(shù)標(biāo)簽使代碼有更強(qiáng)的可讀性昆婿。

  • 在參數(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ù)值能庆,也是實(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ù)是個(gè)變量渠旁。

var ar = [Int]()

// 參數(shù)類型前加 inout 表示是輸入輸出參數(shù)攀例,可以修改
func add(array:  inout [Int]) -> [Int] {
    for i in 1...5{
        array.append(i)
    }
    return array
}

// 調(diào)用的時(shí)候?qū)崊⑶懊婕?&,表示這個(gè)參數(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一樣都是用于模塊之間通訊的承耿。

  • 閉包可以捕獲上下文中的變量。
  • 閉包就是一個(gè)匿名的函數(shù)體伪煤。
  • Java 中的lambda就是一個(gè)匿名內(nèi)部類加袋。

6.1 閉包表達(dá)式語法

{(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 的表達(dá)式擁有更簡(jiǎn)潔的風(fēng)格。

  • 利用上下文推斷參數(shù)和返回值類型
  • 隱式返回單表達(dá)式閉包抱既,單表達(dá)式閉包可以省略return關(guān)鍵字职烧。
  • 參數(shù)名稱縮寫。
  • 尾隨閉包語法防泵。

根據(jù)上下文推斷類型

因?yàn)殚]包是作為函數(shù)的參數(shù)傳入的蚀之,可以根據(jù)參數(shù)的類型來推斷閉包的類型,所以閉包的 參數(shù)類型返回類型 都可以省略捷泞。

names.sort(by: { s1, s2 in return s1 < s2 })

單表達(dá)式隱式返回

names.sort(by: { s1,s2 in s1 > s2 })

參數(shù)名縮寫

names.sort(by:{ $0 > $1})

運(yùn)算符方法

names.sort(by: > )

6.2 尾隨閉包

如果將閉包表達(dá)式作為最后一個(gè)參數(shù)傳遞給函數(shù)足删,將這個(gè)閉包替換成尾隨閉包的形式。

尾隨閉包不用寫參數(shù)標(biāo)簽锁右。

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函數(shù)體部分
}

// 以下是不使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure(closure: {
    // 閉包主體部分
})

// 以下是使用尾隨閉包進(jìn)行函數(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賦值給一個(gè)全局變量,f2一直在內(nèi)存中兄旬,f2依賴于f1狼犯,因此f1也始終在內(nèi)存中,不會(huì)在調(diào)用結(jié)束后领铐,被垃圾回收機(jī)制回收悯森。

閉包是引用類型,一個(gè)對(duì)象屬性賦值給一個(gè)閉包绪撵,如果閉包直接訪問了該對(duì)象或該對(duì)象的成員呐馆,就會(huì)引起循環(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 自動(dòng)閉包

var count = 10
let f = { count += 10 }

print(count)
f()
print(count)

7. 類

7.1 屬性

7.1.1 存儲(chǔ)屬性

  • 可以是 let var
  • 要么默認(rèn)初始化谒兄,要么init構(gòu)造器初始化
  • 可選類型的存儲(chǔ)屬性摔桦,沒有在構(gòu)造器初始化,會(huì)有默認(rèn)初始化 nil
  • 結(jié)構(gòu)體和枚舉賦值給常量承疲,它的變量存儲(chǔ)屬性也不能修改邻耕。
class Person{
    let id: Int
    var name: String = "wangbo"
    // var bb: String
    // 如果沒有默認(rèn)初始化,就必須在init中初始化
    
    // 延遲加載存儲(chǔ)屬性燕鸽,第一次調(diào)用時(shí)才初始值,延遲屬性必須是var
    lazy var array = Array(repeating: 0, count: 3)
    
    init(id: Int) {
        self.id = id
    }
}
// 存儲(chǔ)屬性也是可以直接修改和取值的
let person = Person(id: 10)
person.name = "hh"
person.array = Array(repeating: 10, count: 3)
print(person.name)

  • 全局變量和局部變量都是存儲(chǔ)型變量兄世。
  • 全局變量都是延遲計(jì)算的,跟延遲存儲(chǔ)屬性類似啊研,但是不用 lazy 標(biāo)志御滩。

7.1.2 計(jì)算屬性

計(jì)算屬性提供一個(gè) getter 和一個(gè)可選的 setter方法。來間接獲取或設(shè)置屬性值党远。

計(jì)算屬性其實(shí)就是 java 里的 gettersetter 方法

class Person{
    var age: Int{
        get{
            return self.age
        }
        set{
            self.age = newValue
        }
    }
}

let person = Person()
person.age = 10
print(person.age)

只讀計(jì)算屬性

class Person{
    // 只讀計(jì)算屬性削解,省略掉 get{ return 10 }
    var age : Int{
        return 10
    }
}

let person = Person()
print(person.age)

7.1.3 屬性觀察器

屬性觀察器一般為存儲(chǔ)屬性提供的,計(jì)算屬性可以沟娱,但是沒必要氛驮,在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)體济似,枚舉矫废,類都可以有方法盏缤。

特殊點(diǎn):swift的類方法,可以用static修飾磷脯,也可以用class修飾蛾找。

區(qū)別:

  • static 修飾的類型方法不能被復(fù)寫娩脾。
  • class 修飾的類方法可以被子類復(fù)寫赵誓。
class Person{
    static let a: String = "hello"
    
    // 實(shí)例方法
    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 的類柿赊,如果存儲(chǔ)屬性沒有指定默認(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è)類必須有一個(gè)指定構(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)造器通過返回一個(gè) nil 表示這是個(gè)可失敗構(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() {
        // 表明子類必須實(shí)現(xiàn)該構(gòu)造器
    }
}

7.3 析構(gòu)器

deinit(){
    // 釋放資源
}

7.3 繼承

swift的類如果不指定父類胰挑,是沒有父類的蔓罚。不像其他語言默認(rèn)繼承 Object類。

子類可以繼承父類的屬性瞻颂,方法豺谈,并重寫父類的屬性和方法。

  • 方法前加 final 修飾符贡这,這個(gè)方法不能被重寫茬末。
  • 類前加 final 修飾符,這個(gè)類不能被繼承盖矫。

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 擴(kuò)展

擴(kuò)展可以在不訪問一個(gè)類湃望,結(jié)構(gòu)體拷橘,枚舉,源代碼的基礎(chǔ)上喜爷,給類冗疮,結(jié)構(gòu)體,枚舉添加一些屬性檩帐,方法术幔,實(shí)現(xiàn)協(xié)議等。替代之前的工具類湃密。

  • 添加計(jì)算型實(shí)例屬性和計(jì)算型類屬性
  • 定義實(shí)例方法和類方法
  • 提供新的構(gòu)造器
  • 定義下標(biāo)
  • 定義和使用新的嵌套類型
  • 使已經(jīng)存在的類型遵循(conform)一個(gè)協(xié)議
extension SomeType {
  // 在這里給 SomeType 添加新的功能
}

在項(xiàng)目中诅挑,擴(kuò)展經(jīng)常用來格式化代碼和實(shí)現(xiàn)工具類四敞。

7.5.1 擴(kuò)展屬性

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 擴(kuò)展構(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 擴(kuò)展方法

extension Int {
   func repetitions(task: () -> Void) {
       for _ in 0..<self {
           task()
       }
   }
 
    mutating func square() {
       self = self * self
   }
}



7.5.4 擴(kuò)展下標(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: 包訪問級(jí)別解滓。相當(dāng)于package。默認(rèn)可寫可不寫筝家。

fileprivate: 訪問級(jí)別所修飾的屬性或者方法在當(dāng)前的 Swift 源文件里可以訪問洼裤。

private:只有同一個(gè)類中的方法屬性才能訪問。

8. 結(jié)構(gòu)體

類和結(jié)構(gòu)的相同點(diǎn):

  • 都有存儲(chǔ)屬性和計(jì)算屬性
  • 都可以定義方法
  • 定義下表操作
  • 定義構(gòu)造器
  • 通過擴(kuò)展以增加默認(rèn)實(shí)現(xiàn)之外的功能
  • 遵循協(xié)議

類和結(jié)構(gòu)的不同點(diǎn):

  • 類是引用類型溪王,結(jié)構(gòu)體是值類型
  • 結(jié)構(gòu)體不允許繼承腮鞍,就像final class一樣,是個(gè)常量類莹菱。
  • 結(jié)構(gòu)體可以不定義構(gòu)造器移国,默認(rèn)會(huì)有一個(gè)按照屬性次序定義的構(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)造器中修改屬性值掐禁。如果強(qiáng)行修改怜械,只需在方法前加上 mutating 修飾符。

結(jié)構(gòu)體如果沒有定義構(gòu)造器傅事,會(huì)有一個(gè)默認(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 原始值

枚舉成員在定義時(shí)可以被默認(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é)議里可以有屬性驾霜,遵循這個(gè)協(xié)議的類結(jié)構(gòu)體枚舉都必須要有這個(gè)屬性案训。

  • 必須是 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é)議粪糙,用和符號(hào)(&)分開强霎。

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é)議擴(kuò)展

協(xié)議可以通過擴(kuò)展來為遵循協(xié)議的類型提供屬性、方法以及下標(biāo)的實(shí)現(xiàn)蓉冈。

  • 計(jì)算屬性提供默認(rèn)實(shí)現(xiàn)
  • 方法提供默認(rèn)實(shí)現(xiàn)
  • extension Protocol where Self: 類 限定了協(xié)議Protocol的擴(kuò)展實(shí)現(xiàn)城舞,只能由類的對(duì)象調(diào)用
protocol SomeProtocol{
    // 普通方法
    func add(age: Int) -> Int
    // 屬性
    var age: Int{get set}
    // 構(gòu)造器
    init(age: Int)
}

// 協(xié)議擴(kuò)展
extension SomeProtocol{
    // 實(shí)現(xiàn)計(jì)算屬性
    var name: String {
        return "hhh"
    }
    
    // 實(shí)現(xiàn)方法
    func work(here: String) -> String {
        return "我在 \(here) 工作"
    }
}

// 協(xié)議擴(kuò)展實(shí)現(xiàn)的限定,只能由Person對(duì)象調(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 中洒擦,錯(cuò)誤用遵循 Error 協(xié)議的類型的值來表示椿争。這個(gè)空協(xié)議表明該類型可以用于錯(cuò)誤處理怕膛。

12.1 錯(cuò)誤的定義

錯(cuò)誤實(shí)現(xiàn)Error協(xié)議的類熟嫩。一般用枚舉值表示。

enum VendingMachineError: Error {
    case invalidSelection                     //選擇無效
    case insufficientFunds(coinsNeeded: Int) //金額不足
    case outOfStock                             //缺貨
}

12.2 錯(cuò)誤處理

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 是個(gè)可選類型掸茅,效果和上面一樣,try柠逞?是個(gè)簡(jiǎn)潔的語法
let x = try? someThrowingFunction()

12.2.3 try昧狮!

禁止錯(cuò)誤的傳遞。try板壮!認(rèn)為后面的表達(dá)式不會(huì)拋出錯(cuò)誤逗鸣。

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")

12.2.4 throw

錯(cuò)誤的傳遞

func canThrowErrors() throws -> String

func canThrowErrors() throws

13.內(nèi)存管理

swift 和 OC都是引用計(jì)數(shù)管理內(nèi)存,當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù) = 0 時(shí)绰精,就會(huì)被立即回收內(nèi)存撒璧。

JAVA語言是垃圾回收器,只有內(nèi)存壓力觸發(fā)垃圾回收器回收時(shí)笨使,才會(huì)清理內(nèi)存卿樱。

所以,swift的內(nèi)存利用率更高硫椰。JAVA內(nèi)存利用低容易觸發(fā)OOM繁调。

13.1 弱引用

弱引用是個(gè)可選類型,引用對(duì)象可以是個(gè)nil靶草。不會(huì)持有的對(duì)象保存強(qiáng)引用蹄胰。

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 無主引用

無主引用不是可選類型谦絮,必須有一個(gè)值赡勘。也不會(huì)對(duì)持有的對(duì)象強(qiáng)引用。

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)引用

獲列表中的每一項(xiàng)都由一對(duì)元素組成卖丸,一個(gè)元素是 weakunowned 關(guān)鍵字糠悯,另一個(gè)元素是類實(shí)例的引用(例如 self)或初始化過的變量(如 delegate = self.delegate

lazy var someClosure = {
    // 捕獲列表
    [unowned self, weak delegate = self.delegate] 
    (success, errorCode, errorMsg)
    in
    // 這里是閉包的函數(shù)體
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帮坚,一起剝皮案震驚了整個(gè)濱河市妻往,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌试和,老刑警劉巖讯泣,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異阅悍,居然都是意外死亡好渠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門节视,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拳锚,“玉大人,你說我怎么就攤上這事寻行』舨簦” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵拌蜘,是天一觀的道長杆烁。 經(jīng)常有香客問我,道長简卧,這世上最難降的妖魔是什么兔魂? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮举娩,結(jié)果婚禮上析校,老公的妹妹穿的比我還像新娘。我一直安慰自己铜涉,他們只是感情好智玻,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骄噪,像睡著了一般尚困。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上链蕊,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天事甜,我揣著相機(jī)與錄音,去河邊找鬼滔韵。 笑死逻谦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的陪蜻。 我是一名探鬼主播邦马,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了滋将?” 一聲冷哼從身側(cè)響起邻悬,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎随闽,沒想到半個(gè)月后父丰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掘宪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年蛾扇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魏滚。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镀首,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鼠次,到底是詐尸還是另有隱情更哄,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布须眷,位于F島的核電站竖瘾,受9級(jí)特大地震影響沟突,放射性物質(zhì)發(fā)生泄漏花颗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一惠拭、第九天 我趴在偏房一處隱蔽的房頂上張望扩劝。 院中可真熱鬧,春花似錦职辅、人聲如沸棒呛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽簇秒。三九已至,卻和暖如春秀鞭,著一層夾襖步出監(jiān)牢的瞬間趋观,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工锋边, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皱坛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓豆巨,卻偏偏與公主長得像剩辟,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345