Swift3.0 - 真的很簡(jiǎn)單
Swift3.0 - 數(shù)據(jù)類型
Swift3.0 - Array
Swift3.0 - 字典
Swift3.0 - 可選值
Swift3.0 - 集合
Swift3.0 - 流控制
Swift3.0 - 對(duì)象和類
Swift3.0 - 屬性
Swift3.0 - 函數(shù)和閉包
Swift3.0 - 初始化和釋放
Swift3.0 - 協(xié)議protocol
Swift3.0 - 類和結(jié)構(gòu)體的區(qū)別
Swift3.0 - 枚舉
Swift3.0 - 擴(kuò)展
Swift3.0 - 下標(biāo)
Swift3.0 - 泛型
Swift3.0 - 異常錯(cuò)誤
Swift3.0 - 斷言
Swift3.0 - 自動(dòng)引用計(jì)數(shù)(strong,weak,unowned)
Swift3.0 - 檢測(cè)API
Swift3.0 - 對(duì)象的標(biāo)識(shí)
Swift3.0 - 注釋
Swift3.0 - 元類型
Swift3.0 - 空間命名
Swift3.0 - 對(duì)象判等
Swift3.0 - 探究Self的用途
Swift3.0 - 類簇
Swift3.0 - 動(dòng)態(tài)調(diào)用對(duì)象(實(shí)例)方法
Swift3.0 - 文本輸出
Swift3.0 - 黑魔法swizzle
Swift3.0 - 鏡像
Swift3.0 - 遇到的坑
函數(shù)的幾種類型
- 無參無返
func greet() -> Void {
}
// 或者
func greet(){
}
- 有參無返
func greet(person: String, day: String) {
return "Hello \\\\(person), today is \\\\(day)."
}
greet(person: "Bob", day: "Tuesday")
思考1: 如何省略外部參數(shù)名?
greet("John", "Wednesday")
// 實(shí)現(xiàn)代碼
func greet(_ person: String, _ day: String) -> String {
return "Hello \\\\(person), today is \\\\(day)."
}
- 有參有返
func greet(_ person: String, on day: String) {
return "Hello \\\\(person), today is \\\\(day)."
}
- 無參有返
func greet(_ person: String, on day: String) -> String {
return "Hello \\\\(person), today is \\\\(day)."
}
中級(jí)思考
- 參數(shù)和返回值
1.參數(shù)可以是那些道批?
基本類型的值,對(duì)象,數(shù)組,字典,元組,可變數(shù)量的參數(shù),函數(shù),閉包函數(shù),協(xié)議,結(jié)構(gòu)體,枚舉值
2.怎么定義參數(shù)
a. 單值
func calculate(a:Int){
let b = a
}
b.多值
func calculate(a:Int...){
for _ in a{
}
}
// 調(diào)用
calculate(a: 1,2,3,4,5,6)
c.元組
func calculate(a:(name:String,age:Int)){
let name = a.name;
let age = a.age;
}
d.數(shù)組
func calculate(a:[String]){
for student in a {
}
}
e.定義字典
func calculate(a:[String:Int]){
for student in a {
print(student.key)
print(student.value)
}
}
f.函數(shù)作為參數(shù)
func add(a:Int,b:Int)->Int{// 作為函數(shù)參數(shù)的函數(shù)
return a+b
}
func calculate(a:(Int,Int)->Int){// 定義的參數(shù)為函數(shù)的函數(shù)
a(2,1)// 執(zhí)行函數(shù)
}
calculate(a: add);// 執(zhí)行函數(shù)
g.上面函數(shù)的閉包寫法
calculate { (a,b) -> Int in
return a+b
}
calculate { (a,b) in a+b } // 省略寫法(由于swift有推斷能力,這樣寫它就能幫你推斷出來上面的寫法)
h. 參數(shù)為協(xié)議的方法
protocol Player{ // 定義協(xié)議
func play()
}
func playMusicWithPlayer(player:Player){
player.play()
}
i.參數(shù)為結(jié)構(gòu)體
struct Student{
var name:String
var age:Int
};
func getStudentDescription(student:Student){
print(student.name)
print(student.age)
}
j.參數(shù)為枚舉類型
// 定義枚舉值
enum CarType:String{
case Lincoln = "林肯"
case MERCURY = "水星"
case SUZUKI = "鈴木"
}
// 參數(shù)為協(xié)議的方法
func describeCar(carType:CarType){
print(carType.rawValue);
}
- 函數(shù)的內(nèi)部定義函數(shù)
需求: 創(chuàng)建一個(gè)接口,輸入true 返回 兩個(gè)數(shù)相加的函數(shù),輸入false 返回兩個(gè)數(shù)相減的函數(shù)
func generateFuncByFlag(flag:Bool)->(Int,Int)->Int{
// 定義兩數(shù)字相加函數(shù)
func add(a:Int,b:Int)->Int{
return a+b;
}
// 定義兩數(shù)字相減函數(shù)
func decrease(a:Int,b:Int)->Int{
return a-b;
}
// 根據(jù)輸入的條件返回對(duì)應(yīng)的函數(shù)
if flag{
return add
}else{
return decrease
}
}
// 生成對(duì)應(yīng)的函數(shù)
let addFunc = generateFuncByFlag(flag: false)
// 執(zhí)行返回的函數(shù)
print(addFunc(1,2))
- 設(shè)置默認(rèn)參數(shù)值
func addStudent(student:(name:String,score:Double)=("姓名",12)){
print(student.name)
print(student.1)
}
addStudent()
addStudent(student: ("酷走天涯",99))
提示:
元組類型,不能分別給參數(shù)賦值,比如像下面這樣
// 這樣是錯(cuò)誤的方式
func addStudent(student:(name:String = "酷走天涯",score:Double = 12 )){
print(student.name)
print(student.1)
}
- inout的使用
需求: 創(chuàng)建一個(gè)函數(shù),交換兩個(gè)Int類型值
a.如果參數(shù)為let修飾的常量
func swapTwoInts( a: Int, b: Int){
let temporaryA = a
a = b
b = temporaryA
}
提示:
報(bào)錯(cuò):系統(tǒng)提示錯(cuò)誤,說常量不能修改值
b.我們將參數(shù)變成變量var
func swapTwoInts( var a: Int, var b: Int){
let temporaryA = a
a = b
b = temporaryA
}
提示:
報(bào)錯(cuò),不能使用var 修飾參數(shù)
c.inout 修飾的參數(shù)可以修改值
func swapTwoInts( a: inout Int, b:inout Int){
let temporaryA = a
a = b
b = temporaryA
}
var a = 30
var b = 40
swapTwoInts(a: &a, b: &b)
print(a)
print(b)
運(yùn)行結(jié)果:
40
30
你需要注意的
1.inout的位置 在: 后面,數(shù)據(jù)類型前面
2.inout 修飾的參數(shù)不能有默認(rèn)值
3.inout 不能用于修飾多值(如a:Int...)
- 定義函數(shù)類型的變量
func swapTwoInts( a: inout Int , b:inout Int){
let temporaryA = a
a = b
b = temporaryA
}
var swap1:( inout Int, inout Int)->Void = swapTwoInts
注意:函數(shù)類型的變量不能用標(biāo)簽修飾參數(shù)
// 錯(cuò)誤的寫法 不能使用a,b標(biāo)簽
var swap1:( a :inout Int, b: inout Int)->Void = swapTwoInts
// 你應(yīng)該像下面這樣
var swap1:( _ :inout Int, _: inout Int)->Void = swapTwoInts
// 或者下面這樣也可以,a,b 不一定要和實(shí)際函數(shù)對(duì)應(yīng)
var swap1:( _ a:inout Int, _ b: inout Int)->Void = swapTwoInts
// 建議還是用下面這種
var swap1:( inout Int, inout Int)->Void = swapTwoInts
- 定義閉包類型數(shù)據(jù)
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let customerProvider = { customersInLine.remove(at: 0)}
print(customersInLine.count)
print("Now serving \\\\(customerProvider())!")
print(customersInLine.count)
運(yùn)行結(jié)果:
5
Now serving Chris!
4
提示:上面那種閉包其實(shí)是五參有返的閉包形式,原形如下
let customerProvider:()->String= { customersInLine.remove(at: 0)}
- 關(guān)鍵字 @discardableResult
先看一段代碼:
class OSStudent{
var name:String!
var score:Double!
func setNewScore(score:Double)->Bool{
if name == nil || name.isEmpty{
return false
}
self.score = score
return true
}
}
OSStudent().setNewScore(score: 34.0)
注意:
函數(shù)的setNewScore 方法有返回值,但是調(diào)用的時(shí)候,沒有使用常量或者變量接受這個(gè)返回值,系統(tǒng)會(huì)產(chǎn)生警告如下圖
我們通過加關(guān)鍵字@discardableResult去除那種警告
@discardableResult
func setNewScore(score:Double)->Bool{
if name == nil || name.isEmpty{
return false
}
self.score = score
return true
}
注意
如果你沒有添加這個(gè)關(guān)鍵字,系統(tǒng)默認(rèn)添加的是 @warn_unused_result ,有返回值沒有使用會(huì)發(fā)生警告
高級(jí)思考
- 如何獲取,函數(shù)自己的名稱,在那個(gè)文件中,在文件多少行
// 定義一個(gè)獲取獲取函數(shù)名稱,獲取文件路徑的函數(shù)
func getFunctionName(name:String = #function,line:Int = #line,file:String = #file){
print(name)
print(line)
print(file)
}
// 比如我們要獲取下面函數(shù)的信息,只需要將函數(shù)寫入要獲取信息函數(shù)的內(nèi)部調(diào)用即可
func getUserName(){
getFunctionName()
}
// 執(zhí)行函數(shù)
getUserName()
運(yùn)行結(jié)果:
getUserName()
152
/var/folders/gk/zc__29js08g1g03xrzgl8m1m0000gn/T/./lldb/2184/playground65.swift
- 編譯器可能沒有那么智能
// 定義一個(gè)父類
class Person{
}
// 定義一個(gè)男人
class Man:Person{
}
// 定義一個(gè)女人
class Woman:Person{
}
// 定義三個(gè)描述人的方法
func describePerson(_ person:Person){
print("我是人類")
}
func describePerson(_ woman:Woman){
print("我是女人")
}
func describePerson(_ person:Man){
print("我是男人")
}
// 定義一個(gè)描述男人的女人的方法
func descripePerson(_ person:Person,_ woman:Woman){
describePerson(person)
describePerson(woman)
}
// 執(zhí)行
descripePerson(Man(), Woman())
結(jié)果:
我是人類
我是女人
分析:
參數(shù)man 在值沒有傳入之前,被默認(rèn)為Person 進(jìn)行編譯了,所以不管我們傳入男人或者女人都之調(diào)用人類描述的方法错英。
那么我們應(yīng)該怎么處理這個(gè)問題呢?
func descripePerson(_ person:Person,_ woman:Woman){
if person is Woman{
describePerson(person as! Woman)
}else{
describePerson(person as! Man)
}
describePerson(woman)
}
運(yùn)行結(jié)果:
我是男人
我是女人
下面這種寫法也是可以的
func descripePerson(_ person:Person,_ woman:Woman){
if let woman = person as? Woman{
describePerson(woman)
}else{
describePerson(person as! Man)
}
describePerson(woman)
}
- 泛型
需求: 設(shè)計(jì)一個(gè)接口,交換兩個(gè)元素(數(shù)字,字符,對(duì)象)的值
func swap<T>(a:inout T,b:inout T){
(a,b) = (b,a)
}
測(cè)試1
var a = "你好"
var b = "酷走天涯"
print("交換前---------------------")
print(a)
print(b)
swap(&a, &b)
print("交換后----------------------")
print(a)
print(b)
運(yùn)行結(jié)果:
交換前---------------------
你好
酷走天涯
交換后----------------------
酷走天涯
你好
測(cè)試2
class Woman{
var name = "女人"
init(name:String) {
self.name = name
}
}
print("交換前---------------------")
print(a.name)
print(b.name)
swap(&a, &b)
print("交換后----------------------")
print(a.name)
print(b.name)
運(yùn)行:
交換前---------------------
小紅
小白
交換后----------------------
小白
小紅
提示
交換的必須是相同的對(duì)象
*@escaping 用法
var downloadComplate:(Bool)->()
func downloadResource(url:String,complate:(Bool)->()){
downloadComplate = complate
// 異步下載,下載完成調(diào)動(dòng)
downloadComplate(true)
// 下載失敗
downloadComplate(false)
}
運(yùn)行
編譯報(bào)錯(cuò),提示沒有加@escaping
@escaping 作用
我們經(jīng)常在下載等異步操作完成時(shí),才調(diào)用閉包函數(shù),我們有可能暫時(shí)不要把這個(gè)閉包存放在數(shù)組中,或者使用屬性去引用它,那么這個(gè)時(shí)候就需要使用這個(gè)關(guān)鍵了
修改代碼
var downloadComplate:((Bool)->())
func downloadResource(url:String,complate:@escaping (Bool)->()) {
downloadComplate = complate
// 異步下載,下載完成調(diào)動(dòng)
downloadComplate(true)
// 下載失敗
downloadComplate(false)
}
報(bào)錯(cuò)提示:
downloadComplate 使用之前必須初始化
所以進(jìn)行初始化
var downloadComplate:((Bool)->())! // 加? 也可以,但是在調(diào)用時(shí),要進(jìn)行解包
func downloadResource(url:String,complate:@escaping (Bool)->()) {
downloadComplate = complate
// 異步下載,下載完成調(diào)動(dòng)
downloadComplate(true)
// 下載失敗
downloadComplate(false)
}
我們?nèi)绾握{(diào)用
downloadResource(url: "www.baidu.com") { (flag) in
print(flag)
}
如果我們不需要引用完全可以不使用關(guān)鍵字@escaping
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
- 關(guān)鍵字@autoclosure 的用法
a.不加自動(dòng)閉包的關(guān)鍵字@autoclosure
func serve(customer customerProvider: () -> String) {
print(customerProvider())
}
serve { () -> String in
return "沒加@autoclosure"
}
運(yùn)行結(jié)果:
沒加@autoclosure
b.添加@autoclouse
func serve(customer customerProvider: @autoclosure () -> String) {
print (customerProvider())
}
serve(customer: "加了@autoclosure") // 調(diào)用
是不是感覺參數(shù)像是字符串,而是下面這樣,系統(tǒng)幫你自動(dòng)閉包了
serve(customer: { "加了@autoclosure"})
如果還不清楚,其實(shí)是參數(shù)是一個(gè)返回值
serve(customer: { return "加了@autoclosure"})
完整的寫法其實(shí)是下面這樣
serve(customer: { () in return "加了@autoclosure"})
c. @autoclosure 和 @escaping 組合使用方法
func serve(customer customerProvider: @autoclosure @escaping() -> String) {
customerProvider1 = customerProvider
print (customerProvider())
}
serve(customer: customersInLine.remove(at: 0))
提示:
其實(shí)自動(dòng)閉包給人可能造成一種表意不清的感覺,建議使用的時(shí)候,一定要注釋說明,或者不要使用。
d. @noescape
func calculate(fun :@noescape ()->()){
}
提示:
1.系統(tǒng)默認(rèn)為@onescape 的類型
2.不能被引用
3.不能在異步執(zhí)行