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