Swift 介紹
簡(jiǎn)介
- Swift 語(yǔ)言由蘋(píng)果公司在 2014 年推出,用來(lái)撰寫(xiě) OS X 和 iOS 應(yīng)用程序
- 2014 年,在 Apple WWDC 發(fā)布
- 幾家歡喜,幾家愁
- 愁者:只學(xué)Object-C的人
- 歡喜者:之前做過(guò)java/python/js語(yǔ)言的人
歷史
- 2010 年 7 月,蘋(píng)果開(kāi)發(fā)者工具部門(mén)總監(jiān)
Chris Lattner開(kāi)始著手 Swift 編程語(yǔ)言的設(shè)計(jì)工作 - 用一年時(shí)間,完成基本架構(gòu)
- Swift 大約歷經(jīng) 4 年的開(kāi)發(fā)期,2014 年 6 月發(fā)表
-
克里斯·拉特納何許人?LLVM 項(xiàng)目的主要發(fā)起人與作者之一Clang 編譯器的作者蘋(píng)果公司『開(kāi)發(fā)者工具』部門(mén)的主管領(lǐng)導(dǎo)Xcode、Instruments等編譯器團(tuán)隊(duì)Swift的大部分基礎(chǔ)架構(gòu)均由他1人完成評(píng)價(jià):大神中的大神牛逼中的牛逼
特點(diǎn)
- 特點(diǎn)
- 從它的語(yǔ)法中能看到Objective-C、JavaScript、C#、Python等語(yǔ)言的影子
- 語(yǔ)法簡(jiǎn)單、代碼簡(jiǎn)潔、使用方便
- 可與Objective-C混合使用(相互調(diào)用)
- 提供了類似 Java 的名字空間(namespace)、泛型(generic)、運(yùn)算對(duì)象重載(operator overloading)
- 為什么設(shè)計(jì)Swift語(yǔ)言
- 讓?xiě)?yīng)用開(kāi)發(fā)更簡(jiǎn)單、更快、更穩(wěn)定
- 確保最終應(yīng)用有著更好的質(zhì)量
重要性
- 蘋(píng)果目前在大力推廣Swift
- 斯坦福大學(xué)的公開(kāi)課目前也是使用Swift在授課.因?yàn)橐院骃wift必將代替OC
- 題外話:我們同學(xué)去面試,面試官問(wèn)是否會(huì)Swift,如果會(huì),我們下個(gè)項(xiàng)目直接用Swift來(lái)寫(xiě).你可以教我們Swift.
- 個(gè)人建議:
- 先掌握Swift最基本的語(yǔ)法
- 高級(jí)/特殊的功能隨著學(xué)習(xí)的深入再深入研究
- 千萬(wàn)不要浮躁(前面班級(jí)經(jīng)驗(yàn))
- Swift并不難
- 但是語(yǔ)法和OC區(qū)別非常非常大
- 如果是一個(gè)聽(tīng)一聽(tīng),聽(tīng)不懂就算了的心態(tài).一定是學(xué)不好的
- 如果想要學(xué)習(xí),就認(rèn)真聽(tīng)講,好好練習(xí)
資源網(wǎng)站
- 《The Swift Programming Language》中文版 http://numbbbbb.gitbooks.io/-the-swift-programming-language-/
- swifter 作者王巍,需要付費(fèi)購(gòu)買(mǎi) http://onevcat.com
Swift初體驗(yàn)
- Playground是什么?
- 從Xcode6開(kāi)始出現(xiàn)(Swift開(kāi)始出現(xiàn))
- 翻譯為:操場(chǎng)/游樂(lè)場(chǎng)
- 對(duì)于學(xué)習(xí)Swift基本語(yǔ)法非常方便
- 所見(jiàn)即所得(快速查看結(jié)果)
- 語(yǔ)法特性發(fā)生改變時(shí),可以快速查看.
- Swift最基本的語(yǔ)法變化
- 導(dǎo)入框架 import UIKit
- 定義標(biāo)識(shí)符時(shí),必須聲明該標(biāo)識(shí)符是變量還是常量
- 聲明標(biāo)識(shí)符的格式:變量/常量關(guān)鍵字 名稱 : 數(shù)據(jù)類型
- 語(yǔ)句結(jié)束時(shí)不需要加;
- 如果同一行有多個(gè)語(yǔ)句,則依然需要加
- 但是不建議一行多條語(yǔ)句
- Swift中的打印語(yǔ)句:print(打印的內(nèi)容)
常量&變量
什么是常量和變量
- 在Swift中規(guī)定:在定義一個(gè)標(biāo)識(shí)符時(shí)必須明確說(shuō)明該標(biāo)識(shí)符是一個(gè)常量還是變量
- 使用let來(lái)定義常量,定義之后不可以修改
- 使用var來(lái)定義變量,定義之后可以修改
變量的基本使用
import UIKit
let a : Int = 10
// 錯(cuò)誤寫(xiě)法,當(dāng)一個(gè)字段定義為常量時(shí)是不可以修改的
// a = 20
var b : Int = 20
// 因?yàn)閎定義為變量,因此是可以修改的
b = 30
常量和變量的使用注意:
-
注意:
- 在真實(shí)使用過(guò)程中,建議先定義常量,如果需要修改再修改為變量(更加安全)
- 是指向的對(duì)象不可以再進(jìn)行修改.但是可以通過(guò)指針獲得對(duì)象后,修改對(duì)象內(nèi)部的屬性
// 注意:聲明為常量不可以修改的意思是指針不可以再指向其他對(duì)象.但是可以通過(guò)指針拿到對(duì)象,修改其中的屬性 // view : UIView = [[UIView alloc] init]; // Swift對(duì)象中不需要* var view : UIView = UIView() view = UIView() let view1 : UIView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) view1.backgroundColor = UIColor.redColor() // 枚舉類型的用法:類型.枚舉的值 let btn : UIButton = UIButton(type: UIButtonType.Custom) btn.backgroundColor = UIColor.blueColor() btn.setTitle("按鈕", forState: UIControlState.Normal) btn.frame = CGRect(x: 20, y: 20, width: 60, height: 30) view1.addSubview(btn)
Swift中數(shù)據(jù)類型
Swift類型的介紹
Swift中的數(shù)據(jù)類型也有:整型/浮點(diǎn)型/對(duì)象類型/結(jié)構(gòu)體類型等等
先了解整型和浮點(diǎn)型
-
整型
- 有符號(hào)
- Int8 : 有符號(hào)8位整型
- Int16 : 有符號(hào)16位整型
- Int32 : 有符號(hào)32位整型
- Int64 : 有符號(hào)64位整型
- Int : 和平臺(tái)相關(guān)(默認(rèn),相當(dāng)于OC的NSInteger)
- 無(wú)符號(hào)
- UInt8 : 無(wú)符號(hào)8位整型
- UInt16 : 無(wú)符號(hào)16位整型
- UInt32 : 無(wú)符號(hào)32位整型
- UInt64 : 無(wú)符號(hào)64位整型
- UInt : 和平臺(tái)相關(guān)(常用,相當(dāng)于OC的NSUInteger)(默認(rèn))
- 有符號(hào)
-
浮點(diǎn)型
- Float : 32位浮點(diǎn)型
- Double : 64浮點(diǎn)型(默認(rèn))
// 定義一個(gè)Int類型的變量m,并且賦值為10 var m : Int = 10 // 定義一個(gè)Double類型的常量n,并且賦值為3.14 let n : Double = 3.14
Swift中的類型推導(dǎo)
Swift是強(qiáng)類型的語(yǔ)言
Swift中任何一個(gè)標(biāo)識(shí)符都有明確的類型
-
注意:
- 如果定義一個(gè)標(biāo)識(shí)符時(shí)有直接進(jìn)行賦值,那么標(biāo)識(shí)符后面的類型可以省略.
- 因?yàn)镾wift有類型推導(dǎo),會(huì)自動(dòng)根據(jù)后面的賦值來(lái)決定前面的標(biāo)識(shí)符的數(shù)據(jù)類型
- 可以通過(guò)
option+鼠標(biāo)左鍵來(lái)查看變量的數(shù)據(jù)類型
// 定義變量時(shí)沒(méi)有指定明確的類型,但是因?yàn)橘x值給i一個(gè)20.20為整型.因此i為整型 var i = 20 // 錯(cuò)誤寫(xiě)法:如果之后賦值給i一個(gè)浮點(diǎn)型數(shù)值,則會(huì)報(bào)錯(cuò) // i = 30.5 // 正確寫(xiě)法 var j = 3.33 j = 6.66
Swift中基本運(yùn)算
-
Swift中在進(jìn)行基本運(yùn)算時(shí)必須保證類型一致,否則會(huì)出錯(cuò)
- 相同類型之間才可以進(jìn)行運(yùn)算
- 因?yàn)镾wift中沒(méi)有隱式轉(zhuǎn)換
-
數(shù)據(jù)類型的轉(zhuǎn)化
- Int類型轉(zhuǎn)成Double類型:Double(標(biāo)識(shí)符)
- Double類型轉(zhuǎn)成Int類型:Int(標(biāo)識(shí)符)
let a = 10 let b = 3.14 // 錯(cuò)誤寫(xiě)法 // let c = a + b // let c = a * b // 正確寫(xiě)法 let c = Double(a) + b let d = a + Int(b)
邏輯分支
一. 分支的介紹
- 分支即if/switch/三目運(yùn)算符等判斷語(yǔ)句
- 通過(guò)分支語(yǔ)句可以控制程序的執(zhí)行流程
二. if分支語(yǔ)句
-
和OC中if語(yǔ)句有一定的區(qū)別
- 判斷句可以不加()
- 在Swift的判斷句中必須有明確的真假
- 不再有非0即真
- 必須有明確的Bool值
- Bool有兩個(gè)取值:false/true
// 演練一: let a = 10 // 錯(cuò)誤寫(xiě)法: //if a { // print("a") //} // 正確寫(xiě)法 if a > 9 { print(a) } // 演練二: let score = 87 if score < 60 { print("不及格") } else if score <= 70 { print("及格") } else if score <= 80 { print("良好") } else if score <= 90 { print("優(yōu)秀") } else { print("完美") } // 演練三: // 這個(gè)是可選類型,因?yàn)橹挥新暶鞒煽蛇x類型后,才可以判斷是否為空 // 可選類型會(huì)在后續(xù)講解,可先了解即可 let view : UIView? = UIView() // 判斷如果view有值,則設(shè)置背景 // 錯(cuò)誤寫(xiě)法 //if view { // view.backgroundColor = UIColor.redColor() //} if view != nil { view!.backgroundColor = UIColor.redColor() }
三. 三目運(yùn)算符
-
Swift中的三目運(yùn)算保持了和OC一致的風(fēng)格var a = 10 var b = 50 var result = a > b ? a : b println(result)
四.guard的使用
guard是Swift2.0新增的語(yǔ)法
它與if語(yǔ)句非常類似,它設(shè)計(jì)的目的是提高程序的可讀性
-
guard語(yǔ)句必須帶有else語(yǔ)句,它的語(yǔ)法如下:
- 當(dāng)條件表達(dá)式為true時(shí)候跳過(guò)else語(yǔ)句中的內(nèi)容,執(zhí)行語(yǔ)句組內(nèi)容
guard 條件表達(dá)式 else { // 條換語(yǔ)句 break } 語(yǔ)句組 -
例子
var age = 18 func online(age : Int) -> Void { guard age >= 18 else { print("回家去") return } print("可以上網(wǎng)") } online(age)
四.switch分支
switch的介紹
- Switch作為選擇結(jié)構(gòu)中必不可少的語(yǔ)句也被加入到了Swift中
- 只要有過(guò)編程經(jīng)驗(yàn)的人對(duì)Switch語(yǔ)句都不會(huì)感到陌生
- 但蘋(píng)果對(duì)Switch進(jìn)行了大大的增強(qiáng),使其擁有其他語(yǔ)言中沒(méi)有的特性
switch的簡(jiǎn)單使用
基本用法和OC用法一致
-
不同之處:
- switch后可以不跟()
- case后可以不跟break(默認(rèn)會(huì)有break)
-
例子:
let sex = 0 switch sex { case 0 : print("男") case 1 : print("女") default : print("其他") } -
簡(jiǎn)單使用補(bǔ)充:
- 一個(gè)case判斷中,可以判斷多個(gè)值
- 多個(gè)值以
,隔開(kāi)
let sex = 0 switch sex { case 0, 1: print("正常人") default: print("其他") } -
簡(jiǎn)單使用補(bǔ)充:
- 如果希望出現(xiàn)之前的case穿透,則可以使用關(guān)鍵字
fallthrough
let sex = 0 switch sex { case 0: fallthrough case 1: print("正常人") default: print("其他") } - 如果希望出現(xiàn)之前的case穿透,則可以使用關(guān)鍵字
Switch支持多種數(shù)據(jù)類型
-
浮點(diǎn)型的switch判斷
let f = 3.14 switch f { case 3.14: print("π") default: print("not π") } -
支持字符串類型
- 字符串的使用后面會(huì)詳細(xì)講解
let m = 5 let n = 10 var result = 0 let opration = "+" switch opration { case "+": result = m + n case "-": result = m - n case "*": result = m * n case "/": result = m / n default: result = 0 } print(result)
switch支持區(qū)間判斷
-
什么是區(qū)間?
- 通常我們指的是數(shù)字區(qū)間:010,100200
-
swift中的區(qū)間常見(jiàn)有兩種
- 半開(kāi)半閉區(qū)間:0..<10 表示:0~9,不包括10
- 閉區(qū)間:0...10 表示:0~10
let score = 88 switch score { case 0..<60: print("不及格") case 60..<80: print("幾個(gè)") case 80..<90: print("良好") case 90..<100: print("優(yōu)秀") default: print("滿分") }
循環(huán)的介紹
- 在開(kāi)發(fā)中經(jīng)常會(huì)需要循環(huán)
- 常見(jiàn)的循環(huán)有:for/while/do while.
- 這里我們只介紹for/while,因?yàn)閒or/while最常見(jiàn)
for循環(huán)的寫(xiě)法
-
最常規(guī)寫(xiě)法
// 傳統(tǒng)寫(xiě)法 for var i = 0; i < 10; i++ { print(i) } -
區(qū)間for循環(huán)
for i in 0..<10 { print(i) } for i in 0...10 { print(i) } -
特殊寫(xiě)法
- 如果在for循環(huán)中不需要用到下標(biāo)i for _ in 0..<10 { print("hello") }
while和do while循環(huán)
-
while循環(huán)
- while的判斷句必須有正確的真假,沒(méi)有非0即真
- while后面的()可以省略
var a = 0 while a < 10 { a++ } -
do while循環(huán)
- 使用repeat關(guān)鍵字來(lái)代替了do
let b = 0 repeat { print(b) b++ } while b < 20
字符串的介紹
- 字符串在任何的開(kāi)發(fā)中使用都是非常頻繁的
- OC和Swift中字符串的區(qū)別
- 在OC中字符串類型時(shí)NSString,在Swift中字符串類型是String
- OC中字符串@"",Swift中字符串""
- 使用
String的原因String是一個(gè)結(jié)構(gòu)體,性能更高NSString是一個(gè)OC對(duì)象,性能略差String支持直接遍歷Swift提供了String和NSString之間的無(wú)縫轉(zhuǎn)換
字符的定義
-
定義不可變字符串
let str = "hello Objective-C" -
定義可變字符串
var str = "hello Swift"
字符串的使用
獲取字符串的長(zhǎng)度
-
獲取字符集合,再獲取集合的count屬性
let count = str.characters.count
遍歷字符串
// 字符串遍歷
var str = "Hello, Swift"
for c in str.characters {
print(c)
}
字符串拼接
-
兩個(gè)字符串的拼接
let str1 = "Hello" let str2 = "World" let str3 = str1 + str2 -
字符串和其他數(shù)據(jù)類型的拼接
let name = "why" let age = 18 let info = "my name is \(name), age is \(age)" -
字符串的格式化
- 比如時(shí)間:03:04
let min = 3 let second = 4 let time = String(format: "%02d:%02d", arguments: [min, second])
字符串的截取
-
Swift中提供了特殊的截取方式
- 該方式非常麻煩
- Index創(chuàng)建較為麻煩
-
簡(jiǎn)單的方式是將String轉(zhuǎn)成NSString來(lái)使用
- 在標(biāo)識(shí)符后加:as NSString即可
let myStr = "www.baidu.com" var subStr = (myStr as NSString).substringFromIndex(4) subStr = (myStr as NSString).substringToIndex(3) subStr = (myStr as NSString).substringWithRange(NSRange(location: 4, length: 5)) -
swift截取方式
// 1.定義字符串 let str = "www.baidu.com" // 2.截取開(kāi)始位置 let fromIndex = str.startIndex.advancedBy(3) let header = str.substringFromIndex(fromIndex) // 3.截取結(jié)束位置 let toIndex = str.endIndex.advancedBy(-3) let footer = str.substringToIndex(toIndex) // 4.截取中間的字符串 let range = Range(start: str.startIndex.advancedBy(4), end: str.endIndex.advancedBy(-4)) let middle = str.substringWithRange(range)
數(shù)組
數(shù)組的介紹
- 數(shù)組(Array)是一串有序的由相同類型元素構(gòu)成的集合
- 數(shù)組中的集合元素是有序的,可以重復(fù)出現(xiàn)
- Swift中的數(shù)組
- swift數(shù)組類型是Array,是一個(gè)泛型集合
數(shù)組的初始化
-
數(shù)組分成:可變數(shù)組和不可變數(shù)組
- 使用let修飾的數(shù)組是不可變數(shù)組
- 使用var修飾的數(shù)組是可變數(shù)組
// 定義一個(gè)可變數(shù)組,必須初始化才能使用 var array1 : [String] = [String]() // 定義一個(gè)不可變數(shù)組 let array2 : [NSObject] = ["why", 18] -
在聲明一個(gè)Array類型的時(shí)候可以使用下列的語(yǔ)句之一
var stuArray1:Array<String> var stuArray2: [String] -
聲明的數(shù)組需要進(jìn)行初始化才能使用,數(shù)組類型往往是在聲明的同時(shí)進(jìn)行初始化的
// 定義時(shí)直接初始化 var array = ["why", "lnj", "lmj"] // 先定義,后初始化 var array : Array<String> array = ["why", "lnj", "lmj"]
對(duì)數(shù)組的基本操作
// 添加數(shù)據(jù)
array.append("yz")
// 刪除元素
array.removeFirst()
// 修改元素
array[0] = "why"
// 取值
array[1]
數(shù)組的遍歷
// 遍歷數(shù)組
for i in 0..<array.count {
print(array[i])
}
// forin方式
for item in array {
print(item)
}
// 設(shè)置遍歷的區(qū)間
for item in array[0..<2] {
print(item)
}
// 遍歷數(shù)組的同時(shí)獲取下標(biāo)值
let names = ["why", "yz", "lnj", "lmj"]
for (index, name) in names.enumerate() {
print(index)
print(name)
}
數(shù)組的合并
// 數(shù)組合并
// 注意:只有相同類型的數(shù)組才能合并
var array = ["why", "lmj","lnj"]
var array1 = ["yz", "wsz"]
var array2 = array + array1;
// 不建議一個(gè)數(shù)組中存放多種類型的數(shù)據(jù)
var array3 = [2, 3, "why"]
var array4 = ["yz", 23]
array3 + array4
字典
字典的介紹
- 字典允許按照某個(gè)鍵來(lái)訪問(wèn)元素
- 字典是由兩部分集合構(gòu)成的,一個(gè)是鍵(key)集合,一個(gè)是值(value)集合
- 鍵集合是不能有重復(fù)元素的,而值集合是可以重復(fù)的,鍵和值是成對(duì)出現(xiàn)的
- Swift中的字典
- Swift字典類型是Dictionary,也是一個(gè)泛型集合
字典的初始化
-
Swift中的可變和不可變字典
- 使用let修飾的數(shù)組是不可變字典
- 使用var修飾的數(shù)組是可變字典
// 定義一個(gè)可變字典 var dict1 : [String : NSObject] = [String : NSObject]() // 定義一個(gè)不可變字典 let dict2 = ["name" : "why", "age" : 18] -
在聲明一個(gè)Dictionary類型的時(shí)候可以使用下面的語(yǔ)句之一
var dict1: Dictionary<Int, String> var dict2: [Int: String] -
聲明的字典需要進(jìn)行初始化才能使用,字典類型往往是在聲明的同時(shí)進(jìn)行初始化的
// 定時(shí)字典的同時(shí),進(jìn)行初始化 var dict = ["name" : "why", "age" : 18]
// swift中任意對(duì)象,通常不使用NSObject,使用AnyObject
var dict : Dictionary<String, AnyObject>
dict = ["name" : "why", "age" : 18]
?```
字典的基本操作
// 添加數(shù)據(jù)
dict["height"] = 1.88
dict["weight"] = 70.0
dict
// 刪除字段
dict.removeValueForKey("height")
dict
// 修改字典
dict["name"] = "lmj"
dict.updateValue("lmj", forKey: "name")
dict
// 查詢字典
dict["name"]
字典的遍歷
// 遍歷字典中所有的值
for value in dict.values {
print(value)
}
// 遍歷字典中所有的鍵
for key in dict.keys {
print(key)
}
// 遍歷所有的鍵值對(duì)
for (key, value) in dict {
print(key)
print(value)
}
字典的合并
// 字典的合并
var dict1 = ["name" : "yz", "age" : 20]
var dict2 = ["height" : 1.87, "phoneNum" : "+86 110"]
// 字典不可以相加合并
for (key, value) in dict1 {
dict2[key] = value
}
元組
元組的介紹
- 元組是Swift中特有的,OC中并沒(méi)有相關(guān)類型
- 它是什么呢?
- 它是一種數(shù)據(jù)結(jié)構(gòu),在數(shù)學(xué)中應(yīng)用廣泛
- 類似于數(shù)組或者字典
- 可以用于定義一組數(shù)據(jù)
- 組成元組類型的數(shù)據(jù)可以稱為“元素”
元組的定義
-
元組的常見(jiàn)寫(xiě)法
// 使用元組描述一個(gè)人的信息 ("1001", "張三", 30, 90) // 給元素加上元素名稱,之后可以通過(guò)元素名稱訪問(wèn)元素 (id:"1001", name:"張三", english_score:30, chinese_score:90)
元組的簡(jiǎn)單使用
-
用元組來(lái)描述一個(gè)HTTP的錯(cuò)誤信息
// 元組:HTTP錯(cuò)誤 // let array = [404, "Not Found"] // 寫(xiě)法一: let error = (404, "Not Found") print(error.0) print(error.1) // 寫(xiě)法二: let error = (errorCode : 404, errorInfo : "Not Found") print(error.errorCode) print(error.errorInfo) // 寫(xiě)法三: let (errorCode, errorIno) = (404, "Not Found") print(errorCode) print(errorIno)
可選類型
可選類型的介紹
- 注意:
- 可選類型時(shí)swift中較理解的一個(gè)知識(shí)點(diǎn)
- 暫時(shí)先了解,多利用Xcode的提示來(lái)使用
- 隨著學(xué)習(xí)的深入,慢慢理解其中的原理和好處
- 概念:
- 在OC開(kāi)發(fā)中,如果一個(gè)變量暫停不使用,可以賦值為0(基本屬性類型)或者賦值為空(對(duì)象類型)
- 在swift開(kāi)發(fā)中,nil也是一個(gè)特殊的類型.因?yàn)楹驼鎸?shí)的類型不匹配是不能賦值的(swift是強(qiáng)類型語(yǔ)言)
- 但是開(kāi)發(fā)中賦值nil,在所難免.因此推出了可選類型
- 可選類型的取值:
- 空值
- 有值
定義可選類型
-
定義一個(gè)可選類型有兩種寫(xiě)法
- 最基本的寫(xiě)法
- 語(yǔ)法糖(常用)
// 錯(cuò)誤寫(xiě)法 // let string : String = nil // 正確寫(xiě)法: // 注意:name的類型是一個(gè)可選類型,但是該可選類型中可以存放字符串. // 寫(xiě)法一:定義可選類型 let name : Optional<String> = nil // 寫(xiě)法二:定義可選類型,語(yǔ)法糖(常用) let name : String? = nil
可選類型的使用
// 演練一:給可選類型賦值
// 定義可選類型
var string : Optional<String> = nil
// 給可選類型賦值
// 錯(cuò)誤寫(xiě)法:因此該可選類型中只能存放字符串
string = 123
// 正確寫(xiě)法:
string = "Hello world"
// 打印結(jié)果
print(string)
// 結(jié)果:Optional("Hello world")\n
// 因?yàn)榇蛴〕鰜?lái)的是可選類型,所有會(huì)帶Optional
// 演練二:取出可選類型的值
// 取出可選類型的真實(shí)值(解包)
print(string!)
// 結(jié)果:Hello world\n
// 注意:如果可選類型為nil,強(qiáng)制取出其中的值(解包),會(huì)出錯(cuò)
string = nil
print(string!) // 報(bào)錯(cuò)
// 正確寫(xiě)法:
if string != nil {
print(string!)
}
// 簡(jiǎn)單寫(xiě)法:為了讓在if語(yǔ)句中可以方便使用string
// 可選綁定
if let str = string {
print(str)
}
真實(shí)應(yīng)用場(chǎng)景
-
目的:讓代碼更加嚴(yán)謹(jǐn)
// 通過(guò)該方法創(chuàng)建的URL,可能有值,也可能沒(méi)有值. // 錯(cuò)誤寫(xiě)法:如果返回值是nil時(shí),就不能接收了 // 如果字符串中有中文,則返回值為nil,因此該方法的返回值就是一個(gè)可選類型,而使用一個(gè)NSURL類型接收是錯(cuò)誤的 let url : NSURL = NSURL(string: "www.baidu.com") // 正確寫(xiě)法:使用可選類型來(lái)接收 let url : NSURL? = NSURL(string: "www.baidu.com") // 該方式利用類型推導(dǎo) let url = NSURL(string: "www.baidu.com") // 通過(guò)url來(lái)創(chuàng)建request對(duì)象:在使用可選類型前要先進(jìn)行判斷是否有值 // 該語(yǔ)法成為可選綁定(如果url有值就解包賦值給tempURL,并且執(zhí)行{}) if let tempUrl = url { let request = NSURLRequest(URL: tempUrl) }
類型轉(zhuǎn)化
常見(jiàn)的類型轉(zhuǎn)化符號(hào)
- is : 用于判斷一個(gè)實(shí)例是否是某一種類型
- as : 將實(shí)例轉(zhuǎn)成某一種類型
例子
// 1.定義數(shù)組
let array : [AnyObject] = [12, "why", 1.88]
// 2.取出數(shù)組中的第一個(gè)元素
let objc = array.first!
// 3.判斷第一個(gè)元素是否是一個(gè)Int類型
if objc is Int {
print("是Int類型")
} else {
print("非Int類型")
}
// 4.將objc轉(zhuǎn)成真正的類型來(lái)使用
// 4.1.as? 將AnyObject轉(zhuǎn)成可選類型,通過(guò)判斷可選類型是否有值,來(lái)決定是否轉(zhuǎn)化成功了
let age = objc as? Int
print(age) // 結(jié)果:Optional(12)
// 4.2.as! 將AnyObject轉(zhuǎn)成具體的類型,但是注意:如果不是該類型,那么程序會(huì)崩潰
let age1 = objc as! Int
print(age1) // 結(jié)果:12
函數(shù)
函數(shù)的介紹
函數(shù)相當(dāng)于OC中的方法
-
函數(shù)的格式如下
func 函數(shù)名(參數(shù)列表) -> 返回值類型 { 代碼塊 return 返回值 } func是關(guān)鍵字,多個(gè)參數(shù)列表之間可以用逗號(hào)(,)分隔,也可以沒(méi)有參數(shù)
使用箭頭“->”指向返回值類型
如果函數(shù)沒(méi)有返回值,返回值為Void.并且“-> 返回值類型”部分可以省略
常見(jiàn)的函數(shù)類型
// 1.沒(méi)有參數(shù),沒(méi)用返回值
func about() -> Void {
print("iphone6s plus")
}
// 調(diào)用函數(shù)
about()
// 簡(jiǎn)單寫(xiě)法
// 如果沒(méi)用返回值,Void可以寫(xiě)成()
func about1() -> () {
print("iphone6s plus")
}
// 如果沒(méi)有返回值,后面的內(nèi)容可以都不寫(xiě)
func about2() {
print("iphone6s plus")
}
about2()
// 2.有參數(shù),沒(méi)用返回值
func callPhone(phoneNum : String) {
print("打電話給\(phoneNum)")
}
callPhone("+86 110")
// 3.沒(méi)用參數(shù),有返回值
func readMessage() -> String {
return "吃飯了嗎?"
}
var str = readMessage()
print(str)
// 4.有參數(shù),有返回值
func sum(num1 : Int, num2 : Int) -> Int {
return num1 + num2
}
var result = sum(20, num2: 30)
print(result)
// 5.有多個(gè)返回值的函數(shù)
let nums = [1, 3, 4, 8, 22, 23]
func getNumCount(nums : [Int]) -> (oddCount : Int, evenCount : Int) {
var oddCount = 0
var evenCount = 0
for num in nums {
if num % 2 == 0 {
oddCount++
} else {
evenCount++
}
}
return (oddCount, evenCount)
}
let result = getNumCount(nums)
result.oddCount
result.evenCount
函數(shù)的使用注意
-
注意一: 外部參數(shù)和內(nèi)部參數(shù)
- 在函數(shù)內(nèi)部可以看到的參數(shù),就是內(nèi)部參數(shù)
- 在函數(shù)外面可以看到的參數(shù),就是外部參數(shù)
- 默認(rèn)情況下,從第二個(gè)參數(shù)開(kāi)始,參數(shù)名稱既是內(nèi)部參數(shù)也是外部參數(shù)
- 如果第一個(gè)參數(shù)也想要有外部參數(shù),可以設(shè)置標(biāo)簽:在變量名前加標(biāo)簽即可
- 如果不想要外部參數(shù),可以在參數(shù)名稱前加_
// num1和a是外部參數(shù)的名稱 func ride(num1 num1 : Int, a num2 : Int, b num3 : Int) -> Int { return num1 * num2 * num3 } var result1 = ride(num1: 20, a: 4, b: 5) // 方法的重載:方法名稱相同,但是參數(shù)不同,可以稱之為方法的重載(了解) func ride(num1: Int, _ num2 :Int) -> Int { return num1 * num2 } var result2 = ride(20, 20) -
注意二: 默認(rèn)參數(shù)
- 某些情況,如果沒(méi)有傳入具體的參數(shù),可以使用默認(rèn)參數(shù)
func makecoffee(type :String = "卡布奇諾") -> String { return "制作一杯\(type)咖啡。" } let coffee1 = makecoffee("拿鐵") let coffee2 = makecoffee() -
注意三: 可變參數(shù)
- swift中函數(shù)的參數(shù)個(gè)數(shù)可以變化,它可以接受不確定數(shù)量的輸入類型參數(shù)
- 它們必須具有相同的類型
- 我們可以通過(guò)在參數(shù)類型名后面加入(...)的方式來(lái)指示這是可變參數(shù)
func sum(numbers:Double...) -> Double { var total: Double = 0 for number in numbers { total += number } return total } sum(100.0, 20, 30) sum(30, 80) -
注意四: 引用類型(指針的傳遞)
- 默認(rèn)情況下,函數(shù)的參數(shù)是值傳遞.如果想改變外面的變量,則需要傳遞變量的地址
- 必須是變量,因?yàn)樾枰趦?nèi)部改變其值
- Swift提供的inout關(guān)鍵字就可以實(shí)現(xiàn)
- 對(duì)比下列兩個(gè)函數(shù)
// 函數(shù)一:值傳遞 func swap(var a : Int, var b : Int) { let temp = a; a = b; b = temp print("a:\(a), b:\(b)") } var a = 10 var b = 20 swap(a, b: b) print("a:\(a), b:\(b)") // 函數(shù)二:指針的傳遞 func swap1(inout a : Int, inout b : Int) { let temp = a a = b b = temp print("a:\(a), b:\(b)") } swap1(&a, b: &b) print("a:\(a), b:\(b)") -
函數(shù)的嵌套使用
- swift中函數(shù)可以嵌套使用
- 即函數(shù)中包含函數(shù),但是不推薦該寫(xiě)法
// 函數(shù)的嵌套 let value = 55 func test() { func demo() { print("demo \(value)") } print("test") demo() } demo() // 錯(cuò)誤 test() // 執(zhí)行函數(shù)會(huì)先打印'test',再打印'demo'
函數(shù)的類型
-
函數(shù)類型的概念
- 每個(gè)函數(shù)都有屬于自己的類型,由函數(shù)的參數(shù)類型和返回類型組成
- 這個(gè)例子中定義了兩個(gè)簡(jiǎn)單的數(shù)學(xué)函數(shù):addTwoInts 和 multiplyTwoInts
- 這兩個(gè)函數(shù)都傳入兩個(gè) Int 類型, 返回一個(gè)合適的Int值
- 這兩個(gè)函數(shù)的類型是 (Int, Int) -> Int
// 定義兩個(gè)函數(shù) func addTwoInts(a : Int, b : Int) -> Int { return a + b } func multiplyTwoInt(a : Int, b : Int) -> Int { return a * b } - 每個(gè)函數(shù)都有屬于自己的類型,由函數(shù)的參數(shù)類型和返回類型組成
-
抽取兩個(gè)函數(shù)的類型,并且使用
// 定義函數(shù)的類型 var mathFunction : (Int, Int) -> Int = addTwoInts // 使用函數(shù)的名稱 mathFunction(10, 20) // 給函數(shù)的標(biāo)識(shí)符賦值其他值 mathFunction = multiplyTwoInt // 使用函數(shù)的名稱 mathFunction(10, 20) -
函數(shù)作為方法的參數(shù)
// 3.將函數(shù)的類型作為方法的參數(shù) func printResult(a : Int, b : Int, calculateMethod : (Int, Int) -> Int) { print(calculateMethod(a, b)) } printResult(10, b: 20, calculateMethod: addTwoInts) printResult(10, b: 20, calculateMethod: multiplyTwoInt) -
函數(shù)作為方法的返回值
// 1.定義兩個(gè)函數(shù) func stepForward(num : Int) -> Int { return num + 1 } func stepBackward(num : Int) -> Int { return num - 1 } // 2.定義一個(gè)變量,希望該變量經(jīng)過(guò)計(jì)算得到0 var num = -4 // 3.定義獲取哪一個(gè)函數(shù) func getOprationMethod(num : Int) -> (Int) -> Int { return num <= 0 ? stepForward : stepBackward } // 4.for玄幻進(jìn)行操作 while num != 0 { let oprationMethod = getOprationMethod(num) num = oprationMethod(num) print(num) }
枚舉類型
枚舉類型的介紹
-
概念介紹
- 枚舉定義了一個(gè)通用類型的一組相關(guān)的值,使你可以在你的代碼中以一個(gè)安全的方式來(lái)使用這些值。
- 在 C/OC 語(yǔ)言中枚舉指定相關(guān)名稱為一組整型值
- Swift 中的枚舉更加靈活,不必給每一個(gè)枚舉成員提供一個(gè)值.也可以提供一個(gè)值是字符串,一個(gè)字符,或是一個(gè)整型值或浮點(diǎn)值
-
枚舉類型的語(yǔ)法
- 使用enum關(guān)鍵詞并且把它們的整個(gè)定義放在一對(duì)大括號(hào)內(nèi)
enum SomeEnumeration { // enumeration definition goes here }
枚舉類型的定義
-
以下是指南針?biāo)膫€(gè)方向的一個(gè)例子
- case關(guān)鍵詞表明新的一行成員值將被定義
- 不像 C 和 Objective-C 一樣,Swift 的枚舉成員在被創(chuàng)建時(shí)不會(huì)被賦予一個(gè)默認(rèn)的整數(shù)值
- 在上面的CompassPoints例子中,North,South,East和West不是隱式的等于0,1,2和3
enum CompassPoint { case North case South case East case West } -
定義方式二:多個(gè)成員值可以出現(xiàn)在同一行上
enum Planet { case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune }
給枚舉類型賦值
-
枚舉類型賦值可以是字符串/字符/整型/浮點(diǎn)型
- 注意如果有給枚舉類型賦值,則必須在枚舉類型后面明確說(shuō)明具體的類型
// 1.枚舉類型的賦值 enum CompassPoint : Int { case North = 1 case South = 2 case East = 3 case West = 4 } enum Planet { case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune } // 2.枚舉類型的使用 let p = Planet(rawValue: 3) if let p = p { switch p { case .Mercury: print("Mercury") case .Venus: print("Venus") case .Earth: print("Mercury") case .Mars: print("Mars") case .Jupiter: print("Jupiter") case .Saturn: print("Saturn") case .Uranus: print("Uranus") case .Neptune: print("Neptune") } }
結(jié)構(gòu)體
結(jié)構(gòu)體的介紹
-
概念介紹
- 結(jié)構(gòu)體(struct)是由一系列具有相同類型或不同類型的數(shù)據(jù)構(gòu)成的數(shù)據(jù)集合
- 結(jié)構(gòu)體(struct)指的是一種數(shù)據(jù)結(jié)構(gòu)
- 結(jié)構(gòu)體是值類型,在方法中傳遞時(shí)是值傳遞
-
結(jié)構(gòu)的定義格式
struct 結(jié)構(gòu)體名稱 { // 屬性和方法 }
為什么需要結(jié)構(gòu)體?
- 先來(lái)看一個(gè)例子
- 我們要計(jì)算平面坐標(biāo)里某個(gè)點(diǎn)距點(diǎn)Center的距離是否小于200
- 算起來(lái)很簡(jiǎn)單,勾股定理就搞定了:
- 其中sqrt(n)用來(lái)計(jì)算n的平方根
- pow(x, n)用來(lái)計(jì)算x的n次方
let centerX : Double = 100
let centerY : Double = 100
func inRange(x : Double, y : Double) -> Bool {
let disX = x - centerX
let disY = y - centerX
let dis = sqrt(pow(disX, 2) + pow(disY, 2))
return dis < 200
}
let x : Double = 100
let y : Double = 1000
inRange(x, y: y)
-
問(wèn)題
- 但是這樣有一個(gè)不足,當(dāng)我們需要比較很多個(gè)點(diǎn)和Center的距離的時(shí)候,這些數(shù)字并不能明確告訴我們它們代表的位置的意義,甚至我們都無(wú)法知道它們代表一個(gè)數(shù)字。
- 如果我們可以像這樣來(lái)比較位置:
- 相比數(shù)字,它們看上去就會(huì)直觀的多
- 而這,就是我們需要自定義struct類型最直接的原因
inRange(location1) inRange(myHome) -
使用結(jié)構(gòu)進(jìn)行改進(jìn)
// 初始化結(jié)構(gòu)體 struct Location { var x : Double var y : Double } // 創(chuàng)建結(jié)構(gòu)體 let location = Location(x: 90, y: 90) // 優(yōu)化剛才的方法 func inRange(location : Location) -> Bool { let disX = location.x - centerX let disY = location.y - centerY let dis = sqrt(pow(disX, 2) + pow(disY, 2)) return dis < 200 } inRange(location)
結(jié)構(gòu)體的增強(qiáng)
-
擴(kuò)充構(gòu)造函數(shù)
- 默認(rèn)情況下創(chuàng)建Location時(shí)使用Location(x: x值, y: y值)
- 但是為了讓我們?cè)谑褂媒Y(jié)構(gòu)體時(shí)更加的靈活,swift還可以對(duì)構(gòu)造函數(shù)進(jìn)行擴(kuò)充
- 擴(kuò)充的注意點(diǎn)
- 在擴(kuò)充的構(gòu)造函數(shù)中必須保證成員變量是有值的
- 擴(kuò)充的構(gòu)造函數(shù)會(huì)覆蓋原有的構(gòu)造函數(shù)
struct Location { var x : Double var y : Double init(x : Double, y : Double) { self.x = x self.y = y } init(xyString : String) { let strs = xyString.componentsSeparatedByString(",") x = Double(strs.first!)! y = Double(strs.last!)! } } let location = Location(x: 100, y: 100) let location1 = Location(xyString: "100,100") -
為結(jié)構(gòu)體擴(kuò)充方法
- 為了讓結(jié)構(gòu)體使用更加靈活,swift的結(jié)構(gòu)體中可以擴(kuò)充方法
- 例子:為了Location結(jié)構(gòu)體擴(kuò)充兩個(gè)方法
- 向水平方向移動(dòng)的方法
- 向垂直方向移動(dòng)的方法
struct Location { var x : Double var y : Double init(x : Double, y : Double) { self.x = x self.y = y } init(xyString : String) { let strs = xyString.componentsSeparatedByString(",") x = Double(strs.first!)! y = Double(strs.last!)! } mutating func moveH(x : Double) { self.x += x } mutating func moveV(y : Double) { self.y += y } } -
注意:
- 如果我們使用的Location不是自己定義的,但是我們?nèi)耘f希望在自己的項(xiàng)目里擴(kuò)展Location的操作
- Swift也能幫我們達(dá)成,這個(gè)機(jī)制,叫做extension
extension Location { mutating func moveH(x : Double) { self.x += x } mutating func moveV(y : Double) { self.y += y } }
Swift中類的使用
主要內(nèi)容
- 類的介紹和定義
- 類的屬性
- 類的構(gòu)造函數(shù)
一. 類的介紹和定義
Swift也是一門(mén)面向?qū)ο箝_(kāi)發(fā)的語(yǔ)言
面向?qū)ο蟮幕A(chǔ)是類,類產(chǎn)生了對(duì)象
-
在Swift中如何定義類呢?
- class是Swift中的關(guān)鍵字,用于定義類
class 類名 : SuperClass { // 定義屬性和方法 } -
注意:
- 定義的類,可以沒(méi)有父類.那么該類是rootClass
- 通常情況下,定義類時(shí).繼承自NSObject(非OC的NSObject)
二. 如何定義類的屬性
類的屬性介紹
- Swift中類的屬性有多種
- 存儲(chǔ)屬性:存儲(chǔ)實(shí)例的常量和變量
- 計(jì)算屬性:通過(guò)某種方式計(jì)算出來(lái)的屬性
- 類屬性:與整個(gè)類自身相關(guān)的屬性
存儲(chǔ)屬性
存儲(chǔ)屬性是最簡(jiǎn)單的屬性,它作為類實(shí)例的一部分,用于存儲(chǔ)常量和變量
可以給存儲(chǔ)屬性提供一個(gè)默認(rèn)值,也可以在初始化方法中對(duì)其進(jìn)行初始化
-
下面是存儲(chǔ)屬性的寫(xiě)法
- age和name都是存儲(chǔ)屬性,用來(lái)記錄該學(xué)生的年齡和姓名
- chineseScore和mathScore也是存儲(chǔ)屬性,用來(lái)記錄該學(xué)生的語(yǔ)文分?jǐn)?shù)和數(shù)學(xué)分?jǐn)?shù)
class Student : NSObject { // 定義屬性 // 存儲(chǔ)屬性 var age : Int = 0 var name : String? var chineseScore : Double = 0.0 var mathScore : Double = 0.0 } // 創(chuàng)建學(xué)生對(duì)象 let stu = Student() // 給存儲(chǔ)屬性賦值 stu.age = 10 stu.name = "why" stu.chineseScore = 89.0 stu.mathScore = 98.0
計(jì)算屬性
計(jì)算屬性并不存儲(chǔ)實(shí)際的值,而是提供一個(gè)getter和一個(gè)可選的setter來(lái)間接獲取和設(shè)置其它屬性
計(jì)算屬性
一般只提供getter方法如果只提供getter,而不提供setter,則該計(jì)算屬性為只讀屬性,并且可以省略get{}
-
下面是計(jì)算屬性的寫(xiě)法
- averageScore是計(jì)算屬性,通過(guò)chineseScore和mathScore計(jì)算而來(lái)的屬性
- 在setter方法中有一個(gè)newValue變量,是系統(tǒng)指定分配的
class Student : NSObject { // 定義屬性 // 存儲(chǔ)屬性 var age : Int = 0 var name : String? var chineseScore : Double = 0.0 var mathScore : Double = 0.0 // 計(jì)算屬性 var averageScore : Double { get { return (chineseScore + mathScore) / 2 } // 沒(méi)有意義,因?yàn)橹螳@取值時(shí)依然是計(jì)算得到的 // newValue是系統(tǒng)分配的變量名,內(nèi)部存儲(chǔ)著新值 set { self.averageScore = newValue } } } // 獲取計(jì)算屬性的值 print(stu.averageScore)
類屬性
類屬性是與類相關(guān)聯(lián)的,而不是與類的實(shí)例相關(guān)聯(lián)
所有的類和實(shí)例都共有一份類屬性.因此在某一處修改之后,該類屬性就會(huì)被修改
類屬性的設(shè)置和修改,需要通過(guò)類來(lái)完成
-
下面是類屬性的寫(xiě)法
- 類屬性使用static來(lái)修飾
- courseCount是類屬性,用來(lái)記錄學(xué)生有多少門(mén)課程
class Student : NSObject { // 定義屬性 // 存儲(chǔ)屬性 var age : Int = 0 var name : String? var chineseScore : Double = 0.0 var mathScore : Double = 0.0 // 計(jì)算屬性 var averageScore : Double { get { return (chineseScore + mathScore) / 2 } // 沒(méi)有意義.newValue是系統(tǒng)分配的變量名,內(nèi)部存儲(chǔ)著新值 set { self.averageScore = newValue } } // 類屬性 static var corseCount : Int = 0 } // 設(shè)置類屬性的值 Student.corseCount = 3 // 取出類屬性的值 print(Student.corseCount)
監(jiān)聽(tīng)屬性的改變
在OC中我們可以重寫(xiě)set方法來(lái)監(jiān)聽(tīng)屬性的改變
Swift中可以通過(guò)屬性觀察者來(lái)監(jiān)聽(tīng)和響應(yīng)屬性值的變化
通常是監(jiān)聽(tīng)存儲(chǔ)屬性和類屬性的改變.(對(duì)于計(jì)算屬性,我們不需要定義屬性觀察者,因?yàn)槲覀兛梢栽谟?jì)算屬性的setter中直接觀察并響應(yīng)這種值的變化)
-
我們通過(guò)設(shè)置以下觀察方法來(lái)定義觀察者
- willSet:在屬性值被存儲(chǔ)之前設(shè)置。此時(shí)新屬性值作為一個(gè)常量參數(shù)被傳入。該參數(shù)名默認(rèn)為newValue,我們可以自己定義該參數(shù)名
- didSet:在新屬性值被存儲(chǔ)后立即調(diào)用。與willSet相同,此時(shí)傳入的是屬性的舊值,默認(rèn)參數(shù)名為oldValue
- willSet與didSet只有在屬性第一次被設(shè)置時(shí)才會(huì)調(diào)用,在初始化時(shí),不會(huì)去調(diào)用這些監(jiān)聽(tīng)方法
-
監(jiān)聽(tīng)的方式如下:
- 監(jiān)聽(tīng)age和name的變化
class Person : NSObject { var name : String? { // 可以給newValue自定義名稱 willSet (new){ // 屬性即將改變,還未改變時(shí)會(huì)調(diào)用的方法 // 在該方法中有一個(gè)默認(rèn)的系統(tǒng)屬性newValue,用于存儲(chǔ)新值 print(name) print(new) } // 可以給oldValue自定義名稱 didSet (old) { // 屬性值已經(jīng)改變了,會(huì)調(diào)用的方法 // 在該方法中有一個(gè)默認(rèn)的系統(tǒng)屬性oldValue,用于存儲(chǔ)舊值 print(name) print(old) } } var age : Int = 0 var height : Double = 0.0 } let p : Person = Person() // 在賦值時(shí),監(jiān)聽(tīng)該屬性的改變 // 在OC中是通過(guò)重寫(xiě)set方法 // 在swift中,可以給屬性添加監(jiān)聽(tīng)器 p.name = "why" //p.name = "yz"
類的構(gòu)造函數(shù)
構(gòu)造函數(shù)的介紹
- 構(gòu)造函數(shù)類似于OC中的初始化方法:init方法
- 默認(rèn)情況下載創(chuàng)建一個(gè)類時(shí),必然會(huì)調(diào)用一個(gè)構(gòu)造函數(shù)
- 即便是沒(méi)有編寫(xiě)任何構(gòu)造函數(shù),編譯器也會(huì)提供一個(gè)默認(rèn)的構(gòu)造函數(shù)。
- 如果是繼承自NSObject,可以對(duì)父類的構(gòu)造函數(shù)進(jìn)行重寫(xiě)
構(gòu)造函數(shù)的基本使用
構(gòu)造函數(shù)的基本使用
類的屬性必須有值
-
如果不是在定義時(shí)初始化值,可以在構(gòu)造函數(shù)中賦值
class Person: NSObject { var name : String var age : Int // 重寫(xiě)了NSObject(父類)的構(gòu)造方法 override init() { name = "" age = 0 } } // 創(chuàng)建一個(gè)Person對(duì)象 let p = Person()
初始化時(shí)給屬性賦值
很多時(shí)候,我們?cè)趧?chuàng)建一個(gè)對(duì)象時(shí)就會(huì)給屬性賦值
可以自定義構(gòu)造函數(shù)
-
注意:如果自定義了構(gòu)造函數(shù),會(huì)覆蓋init()方法.即不在有默認(rèn)的構(gòu)造函數(shù)
class Person: NSObject { var name : String var age : Int // 自定義構(gòu)造函數(shù),會(huì)覆蓋init()函數(shù) init(name : String, age : Int) { self.name = name self.age = age } } // 創(chuàng)建一個(gè)Person對(duì)象 let p = Person(name: "why", age: 18)
字典轉(zhuǎn)模型(初始化時(shí)傳入字典)
真實(shí)創(chuàng)建對(duì)象時(shí),更多的是將字典轉(zhuǎn)成模型
-
注意:
- 去字典中取出的是NSObject,任意類型.
- 可以通過(guò)as!轉(zhuǎn)成需要的類型,再賦值(不可以直接賦值)
class Person: NSObject { var name : String var age : Int // 自定義構(gòu)造函數(shù),會(huì)覆蓋init()函數(shù) init(dict : [String : NSObject]) { name = dict["name"] as! String age = dict["age"] as! Int } } // 創(chuàng)建一個(gè)Person對(duì)象 let dict = ["name" : "why", "age" : 18] let p = Person(dict: dict)
字典轉(zhuǎn)模型(利用KVC轉(zhuǎn)化)
利用KVC字典轉(zhuǎn)模型會(huì)更加方便
-
注意:
- KVC并不能保證會(huì)給所有的屬性賦值
- 因此屬性需要有默認(rèn)值
- 基本數(shù)據(jù)類型默認(rèn)值設(shè)置為0
- 對(duì)象或者結(jié)構(gòu)體類型定義為可選類型即可(可選類型沒(méi)有賦值前為nil)
class Person: NSObject { // 結(jié)構(gòu)體或者類的類型,必須是可選類型.因?yàn)椴荒鼙WC一定會(huì)賦值 var name : String? // 基本數(shù)據(jù)類型不能是可選類型,否則KVC無(wú)法轉(zhuǎn)化 var age : Int = 0 // 自定義構(gòu)造函數(shù),會(huì)覆蓋init()函數(shù) init(dict : [String : NSObject]) { // 必須先初始化對(duì)象 super.init() // 調(diào)用對(duì)象的KVC方法字典轉(zhuǎn)模型 setValuesForKeysWithDictionary(dict) } } // 創(chuàng)建一個(gè)Person對(duì)象 let dict = ["name" : "why", "age" : 18] let p = Person(dict: dict)
類的析構(gòu)函數(shù)
析構(gòu)函數(shù)
-
Swift 會(huì)自動(dòng)釋放不再需要的實(shí)例以釋放資源
- Swift 通過(guò)自動(dòng)引用計(jì)數(shù)(ARC)處理實(shí)例的內(nèi)存管理
- 當(dāng)引用計(jì)數(shù)為0時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)(不可以手動(dòng)調(diào)用)
- 通常在析構(gòu)函數(shù)中釋放一些資源(如移除通知等操作)
-
析構(gòu)函數(shù)的寫(xiě)法
deinit { // 執(zhí)行析構(gòu)過(guò)程 }
示例練習(xí)
class Person {
var name : String
var age : Int
init(name : String, age : Int) {
self.name = name
self.age = age
}
deinit {
print("Person-deinit")
}
}
var p : Person? = Person(name: "why", age: 18)
p = nil
自動(dòng)引用計(jì)數(shù)
工作機(jī)制
- Swift和OC一樣,采用自動(dòng)引用計(jì)數(shù)來(lái)管理內(nèi)容
- 當(dāng)有一個(gè)強(qiáng)引用指向某一個(gè)動(dòng)向時(shí),該對(duì)象的引用計(jì)數(shù)會(huì)自動(dòng)+1
- 當(dāng)該強(qiáng)引用消失時(shí),引用計(jì)數(shù)會(huì)自動(dòng)-1
- 當(dāng)引用計(jì)數(shù)為0時(shí),該對(duì)象會(huì)被銷毀
循環(huán)引用
在通常情況下,ARC是會(huì)自動(dòng)幫助我們管理內(nèi)存的
-
但是在開(kāi)發(fā)中我們經(jīng)常會(huì)出現(xiàn)循環(huán)引用的問(wèn)題,比如下面的示例
- Student對(duì)Book對(duì)象有一個(gè)強(qiáng)引用
- 而B(niǎo)ook對(duì)Student有一個(gè)強(qiáng)引用
- 在兩個(gè)對(duì)象都指向nil時(shí),依然不會(huì)被銷毀,就形成了循環(huán)引用
// 1.創(chuàng)建類 class Student { var book : Book? deinit { print("Student -- deinit") } } class Book { var owner : Student? deinit { print("Book -- deinit") } } // 2.創(chuàng)建對(duì)象 var stu : Student? = Student() var book : Book? = Book() // 3.相互引用 stu?.book = book book?.owner = stu // 4.對(duì)象置nil stu = nil book = nil -
解決方案
- swift提供了兩種解決方案
- weak : 和OC中的__weak一樣是一個(gè)弱引用.當(dāng)指向的對(duì)象銷毀時(shí),會(huì)自動(dòng)將指針指向nil
- unowned : 和OC中的__unsafe_unretained.當(dāng)對(duì)象銷毀時(shí)依然指向原來(lái)的位置(容易引起野指針)
// 1.創(chuàng)建類 class Student { weak var book : Book? // unowned var book : Book = Book() deinit { print("Student -- deinit") } } class Book { var owner : Student? deinit { print("Book -- deinit") } } // 2.創(chuàng)建對(duì)象 var stu : Student? = Student() var book : Book? = Book() // 3.相互引用 stu?.book = book! book?.owner = stu // 4.對(duì)象置nil stu = nil book = nil - swift提供了兩種解決方案
可選鏈
可選連的概念
- 它的可選性體現(xiàn)于請(qǐng)求或調(diào)用的目標(biāo)當(dāng)前可能為空(nil)
- 如果可選的目標(biāo)有值,那么調(diào)用就會(huì)成功;
- 如果選擇的目標(biāo)為空(nil),則這種調(diào)用將返回空(nil)
- 多次調(diào)用被鏈接在一起形成一個(gè)鏈,如果任何一個(gè)節(jié)點(diǎn)為空(nil)將導(dǎo)致整個(gè)鏈?zhǔn)А?/li>
- 可選鏈的使用
- 在可選類型后面放一個(gè)問(wèn)號(hào),可以定義一個(gè)可選鏈。
- 這一點(diǎn)很像在可選值后面放一個(gè)嘆號(hào)來(lái)強(qiáng)制拆得其封包內(nèi)的值
- 它們的主要的區(qū)別在于當(dāng)可選值為空時(shí)可選鏈即刻失敗
- 然而一般的強(qiáng)制解析將會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤。
- 因?yàn)榭蛇x鏈的結(jié)果可能為nil,可能有值.因此它的返回值是一個(gè)可選類型.
- 可以通過(guò)判斷返回是否有值來(lái)判斷是否調(diào)用成功
- 有值,說(shuō)明調(diào)用成功
- 為nil,說(shuō)明調(diào)用失敗
可選鏈的示例
-
從可選鏈中取值
- 示例描述: 人(Person)有一個(gè)狗(Dog),狗(Dog)有一個(gè)玩具(Toy),玩具有價(jià)格(price)
- 使用代碼描述上述信息
// 1.定義類 class Person { var name : String var dog : Dog? init(name : String) { self.name = name } } class Dog { var color : UIColor var toy : Toy? init(color : UIColor) { self.color = color } func runing() { print("跑起來(lái)") } } class Toy { var price : Double = 0.0 } // 2.創(chuàng)建對(duì)象,并且設(shè)置對(duì)象之間的關(guān)系 // 2.1.創(chuàng)建對(duì)象 let person = Person(name: "小明") let dog = Dog(color: UIColor.yellowColor()) let toy = Toy() toy.price = 100.0 // 2.2.設(shè)置對(duì)象之間的關(guān)系 person.dog = dog dog.toy = toy -
需求:獲取
小明的大黃寵物的玩具價(jià)格取出的值為可選類型,因?yàn)榭蛇x鏈中有一個(gè)可選類型為nil,則返回nil因此結(jié)果可能有值,可能為nil.因此是一個(gè)可選類型let price = person.dog?.toy?.price print(price) // Optional(100.0)\n -
需求:給小明的大黃一個(gè)新的玩具
- 相當(dāng)于給可選類型賦值
person.dog?.toy = Toy() -
需求:讓小明的狗跑起來(lái)
- 如果可選類型有值,則會(huì)執(zhí)行該方法
- 如果可選類型為nil,則該方法不會(huì)執(zhí)行
person.dog?.runing()
協(xié)議
協(xié)議的格式
-
協(xié)議的定義方式與類,結(jié)構(gòu)體,枚舉的定義都非常相似
protocol SomeProtocol { // 協(xié)議方法 } -
遵守協(xié)議的格式
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { // 類的內(nèi)容 // 實(shí)現(xiàn)協(xié)議中的方法 }
協(xié)議的基本使用
-
定義協(xié)議和遵守協(xié)議
// 1.定義協(xié)議 protocol SportProtocol { func playBasketball() func playFootball() } // 2.遵守協(xié)議 // 注意:默認(rèn)情況下在swift中所有的協(xié)議方法都是必須實(shí)現(xiàn)的,如果不實(shí)現(xiàn),則編譯器會(huì)報(bào)錯(cuò) class Person : SportProtocol { var name : String? var age : Int = 0 // 實(shí)現(xiàn)協(xié)議中的方法 func playBasketball() { print("人在打籃球") } func playFootball() { print("人在踢足球") } } -
協(xié)議之間的繼承
protocol CrazySportProtocol { func jumping() } protocol SportProtocol : CrazySportProtocol { func playBasketball() func playFootball() }
代理設(shè)計(jì)模式
-
協(xié)議繼承用于代理設(shè)計(jì)模式
protocol BuyTicketProtocol { func buyTicket() } class Person { // 1.定義協(xié)議屬性 var delegate : BuyTicketProtocol // 2.自定義構(gòu)造函數(shù) init (delegate : BuyTicketProtocol) { self.delegate = delegate } // 3.行為 func goToBeijing() { delegate.buyTicket() } } class HuangNiu: BuyTicketProtocol { func buyTicket() { print("買(mǎi)了一張火車票") } } let p = Person(delegate: HuangNiu()) p.goToBeijing() ?```
協(xié)議中方法的可選
// 1.定義協(xié)議
@objc
protocol SportProtocol {
func playBasketball()
optional func playFootball()
}
// 2.遵守協(xié)議
class Person : SportProtocol {
var name : String?
var age : Int = 0
// 實(shí)現(xiàn)協(xié)議中的方法
@objc func playBasketball() {
print("人在打籃球")
}
}
閉包
閉包的介紹
- 閉包和OC中的block非常相似
- OC中的block是匿名的函數(shù)
- Swift中的閉包是一個(gè)特殊的函數(shù)
- block和閉包都經(jīng)常用于回調(diào)
- 注意:閉包和block一樣,第一次使用時(shí)可能不習(xí)慣它的語(yǔ)法,可以先按照使用簡(jiǎn)單的閉包,隨著學(xué)習(xí)的深入,慢慢掌握其靈活的運(yùn)用方法.
閉包的使用
block的用法回顧
-
定義網(wǎng)絡(luò)請(qǐng)求的類
@interface HttpTool : NSObject - (void)loadRequest:(void (^)())callBackBlock; @end @implementation HttpTool - (void)loadRequest:(void (^)())callBackBlock { dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"加載網(wǎng)絡(luò)數(shù)據(jù):%@", [NSThread currentThread]); dispatch_async(dispatch_get_main_queue(), ^{ callBackBlock(); }); }); } @end -
進(jìn)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求到數(shù)據(jù)后利用block進(jìn)行回調(diào)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self.httpTool loadRequest:^{ NSLog(@"主線程中,將數(shù)據(jù)回調(diào).%@", [NSThread currentThread]); }]; } -
block寫(xiě)法總結(jié):
block的寫(xiě)法: 類型: 返回值(^block的名稱)(block的參數(shù)) 值: ^(參數(shù)列表) { // 執(zhí)行的代碼 };
使用閉包代替block
-
定義網(wǎng)絡(luò)請(qǐng)求的類
class HttpTool: NSObject { func loadRequest(callBack : ()->()){ dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("加載數(shù)據(jù)", [NSThread.currentThread()]) dispatch_async(dispatch_get_main_queue(), { () -> Void in callBack() }) } } } -
進(jìn)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求到數(shù)據(jù)后利用閉包進(jìn)行回調(diào)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { // 網(wǎng)絡(luò)請(qǐng)求 httpTool.loadRequest ({ () -> () in print("回到主線程", NSThread.currentThread()); }) } -
閉包寫(xiě)法總結(jié):
閉包的寫(xiě)法: 類型:(形參列表)->(返回值) 技巧:初學(xué)者定義閉包類型,直接寫(xiě)()->().再填充參數(shù)和返回值 值: { (形參) -> 返回值類型 in // 執(zhí)行代碼 }
閉包的簡(jiǎn)寫(xiě)
-
如果閉包沒(méi)有參數(shù),沒(méi)有返回值.in和in之前的內(nèi)容可以省略
httpTool.loadRequest({ print("回到主線程", NSThread.currentThread()); }) -
尾隨閉包寫(xiě)法:
- 如果閉包是函數(shù)的最后一個(gè)參數(shù),則可以將閉包寫(xiě)在()后面
- 如果函數(shù)只有一個(gè)參數(shù),并且這個(gè)參數(shù)是閉包,那么()可以不寫(xiě)
httpTool.loadRequest() { print("回到主線程", NSThread.currentThread()); } // 開(kāi)發(fā)中建議該寫(xiě)法 httpTool.loadRequest { print("回到主線程", NSThread.currentThread()); }
閉包的循環(huán)引用
如果在HttpTool中有對(duì)閉包進(jìn)行強(qiáng)引用,則會(huì)形成循環(huán)引用
-
補(bǔ)充:在Swift中檢測(cè)一個(gè)對(duì)象是否銷毀,可以實(shí)現(xiàn)對(duì)象的
deinit函數(shù)// 析構(gòu)函數(shù)(相當(dāng)于OC中dealloc方法) deinit { print("ViewController----deinit") } -
循環(huán)引用的(實(shí)現(xiàn))
- 該實(shí)現(xiàn)是為了產(chǎn)生循環(huán)引用,而產(chǎn)生的循環(huán)引用
class HttpTool: NSObject { // 定義屬性,來(lái)強(qiáng)引用傳入的閉包 var callBack : (()->())? func loadRequest(callBack : ()->()){ dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("加載數(shù)據(jù)", [NSThread.currentThread()]) dispatch_async(dispatch_get_main_queue(), { () -> Void in callBack() }) } self.callBack = callBack } } swift中解決循環(huán)引用的方式
-
方案一:
- 使用weak,對(duì)當(dāng)前控制器使用弱引用
- 但是因?yàn)閟elf可能有值也可能沒(méi)有值,因此weakSelf是一個(gè)可選類型,在真正使用時(shí)可以對(duì)其強(qiáng)制解包(該處強(qiáng)制解包沒(méi)有問(wèn)題,因?yàn)榭刂破饕欢ù嬖?否則無(wú)法調(diào)用所在函數(shù))
// 解決方案一: weak var weakSelf = self httpTool.loadData { print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread()) weakSelf!.view.backgroundColor = UIColor.redColor() } -
方案二:
- 和方案一類型,只是書(shū)寫(xiě)方式更加簡(jiǎn)單
- 可以寫(xiě)在閉包中,并且在閉包中用到的self都是弱引用
httpTool.loadData {[weak self] () -> () in print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread()) self!.view.backgroundColor = UIColor.redColor() } -
方案三:(常用)
- 使用關(guān)鍵字
unowned - 從行為上來(lái)說(shuō) unowned 更像OC中的 unsafe_unretained
- unowned 表示:即使它原來(lái)引用的對(duì)象被釋放了,仍然會(huì)保持對(duì)被已經(jīng)釋放了的對(duì)象的一個(gè) "無(wú)效的" 引用,它不能是 Optional 值,也不會(huì)被指向 nil
httpTool.loadData {[unowned self] () -> () in print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread()) self.view.backgroundColor = UIColor.redColor() } - 使用關(guān)鍵字
懶加載
懶加載的介紹
- swift中也有懶加載的方式
- (蘋(píng)果的設(shè)計(jì)思想:希望所有的對(duì)象在使用時(shí)才真正加載到內(nèi)存中)
- 和OC不同的是swift有專門(mén)的關(guān)鍵字來(lái)實(shí)現(xiàn)懶加載
- lazy關(guān)鍵字可以用于定義某一個(gè)屬性懶加載
懶加載的使用
-
格式
lazy var 變量: 類型 = { 創(chuàng)建變量代碼 }() -
懶加載的使用
// 懶加載的本質(zhì)是,在第一次使用的時(shí)候執(zhí)行閉包,將閉包的返回值賦值給屬性 // lazy的作用是只會(huì)賦值一次 lazy var array : [String] = { () -> [String] in return ["why", "lmj", "lnj"] }()
常見(jiàn)注釋
單行注釋
Swift 中的注釋與C 語(yǔ)言的注釋非常相似。
-
單行注釋以雙正斜杠(//)作為起始標(biāo)記
// 注釋內(nèi)容
多行注釋
其起始標(biāo)記為單個(gè)正斜杠后跟隨一個(gè)星號(hào)(/*)
-
終止標(biāo)記為一個(gè)星號(hào)后跟隨單個(gè)正斜杠(*/)
/* 這是一個(gè), 多行注釋 */ -
和與 C 語(yǔ)言多行注釋不同,Swift 的多行注釋可以嵌套在其它的多行注釋之中
/* 這是第一個(gè)多行注釋的開(kāi)頭 /* 這是第二個(gè)被嵌套的多行注釋 */ 這是第一個(gè)多行注釋的結(jié)尾 */
文檔注釋
Swift中添加文檔注釋較為簡(jiǎn)單
-
使用(///)可以為方法或者屬性添加文檔注釋
/// 打電話給某人 func callPhone(phoneNum : String) { print("打電話給\(phoneNum)") }
分組注釋
swift中不可以再使用
#pragma mark --
如果打算對(duì)代碼進(jìn)行分組可以使用
// MARK:-方式// MARK:-
訪問(wèn)權(quán)限
swift中的訪問(wèn)權(quán)限
-
Swift 中的訪問(wèn)控制模型基于模塊和源文件這兩個(gè)概念
- internal : 在本模塊中都可以進(jìn)行訪問(wèn) - private : 在當(dāng)前源文件中可以訪問(wèn) - public : 在其他模塊中可以訪問(wèn)
異常處理
異常的介紹
- 只要我們?cè)诰幊?,就一定要面?duì)錯(cuò)誤處理的問(wèn)題。
- Swift在設(shè)計(jì)的時(shí)候就盡可能讓我們明確感知錯(cuò)誤,明確處理錯(cuò)誤
- 比如:只有使用Optional才能處理空值;
- 如何描述一個(gè)錯(cuò)誤?
- 在Swift里,任何一個(gè)遵從ErrorType protocol的類型,都可以用于描述錯(cuò)誤。
- ErrorType是一個(gè)空的protocol,它唯一的功能,就是告訴Swift編譯器,某個(gè)類型用來(lái)表示一個(gè)錯(cuò)誤。
- 通常,我們使用一個(gè)enum來(lái)定義各種錯(cuò)誤的可能性
異常的示例
-
假如我們想要讀取一個(gè)文件中的內(nèi)容,按照OC的邏輯我們可以這樣來(lái)模擬
- 當(dāng)我們調(diào)用方法獲取結(jié)果為nil時(shí),你并不能確定到底參數(shù)了什么錯(cuò)誤得到了nil
func readFileContent(filePath : String) -> String? { // 1.filePath為"" if filePath == "" { return nil } // 2.filepath有值,但是沒(méi)有對(duì)應(yīng)的文件 if filePath != "/User/Desktop/123.plist" { return nil } // 3.取出其中的內(nèi)容 return "123" } readFileContent("abc") -
使用異常對(duì)上述方法進(jìn)行改進(jìn)
// 1.定義異常 enum FileReadError : ErrorType { case FileISNull case FileNotFound } // 2.改進(jìn)方法,讓方法拋出異常 func readFileContent(filePath : String) throws -> String { // 1.filePath為"" if filePath == "" { throw FileReadError.FileISNull } // 2.filepath有值,但是沒(méi)有對(duì)應(yīng)的文件 if filePath != "/User/Desktop/123.plist" { throw FileReadError.FileISNull } // 3.取出其中的內(nèi)容 return "123" } -
處理異常有三種方式
// 3.異常的處理三種方式 // 3.1.try方式,需要手動(dòng)處理異常 do { let result = try readFileContent("abc") } catch { print(error) } // 3.2.try?方式,不處理異常,如果出現(xiàn)了異常,則返回一個(gè)nil.沒(méi)有異常,則返回對(duì)應(yīng)的值 // 最終返回結(jié)果為一個(gè)可選類型 let result = try? readFileContent("abc") // 3.3.try!方法,告訴系統(tǒng)該方法沒(méi)有異常. // 注意:如果出現(xiàn)了異常,則程序會(huì)崩潰 try! readFileContent("abc")
Swift和OC相互調(diào)?用
Swift調(diào)?用OC
- 創(chuàng)建橋接?文件—> .h
- 在橋接?文件中導(dǎo)?入頭?文件
- 配置橋接?文件: 項(xiàng)目->buildSettings —> bridging —> 配置
OC調(diào)?用Swift
- 項(xiàng)?目名字不能隨便起
- Swift中的類/屬性/?方法必須使?用public修飾
- 導(dǎo)?項(xiàng)目名稱-Swift.h