Swift 函數(shù)用來(lái)完成特定任務(wù)的獨(dú)立的代碼塊。
Swift使用一個(gè)統(tǒng)一的語(yǔ)法來(lái)表示簡(jiǎn)單的C語(yǔ)言風(fēng)格的函數(shù)到復(fù)雜的Objective-C語(yǔ)言風(fēng)格的方法。
函數(shù)聲明: 告訴編譯器函數(shù)的名字亚兄,返回類型及參數(shù)。
函數(shù)定義: 提供了函數(shù)的實(shí)體隔躲。
函數(shù)
Swift 函數(shù)包含了參數(shù)類型及返回值類型:
函數(shù)定義
函數(shù)的參數(shù)傳遞的順序必須與參數(shù)列表相同。
函數(shù)的實(shí)參傳遞的順序必須與形參列表相同,-> 后定義函數(shù)的返回值類型。
//語(yǔ)法
func funcname(形參) -> returntype
{
Statement1
Statement2
……
Statement N
return parameters
}
//例子
func runoob(site: String) -> String {
return (site)
}
函數(shù)參數(shù)+不帶參數(shù)函數(shù)+沒(méi)有返回值函數(shù)
函數(shù)可以接受一個(gè)或者多個(gè)參數(shù)量愧,這些參數(shù)被包含在函數(shù)的括號(hào)之中,以逗號(hào)分隔帅矗。
func runoob(name: String, site: String) -> String {
return name + site
}
func sitename() -> String {
return "123"
}
元組作為函數(shù)返回值
函數(shù)返回值類型可以是字符串偎肃,整型,浮點(diǎn)型等浑此。
元組與數(shù)組類似累颂,不同的是,紊馏。
你可以用元組(tuple)類型讓多個(gè)值作為一個(gè)復(fù)合值從函數(shù)中返回。
下面的這個(gè)例子中最冰,定義了一個(gè)名為minMax(_:)的函數(shù)瘦棋,作用是在一個(gè)Int數(shù)組中找出最小值與最大值。
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("最小值為 \(bounds.min) 暖哨,最大值為 \(bounds.max)")
//最小值為 -6 赌朋,最大值為 109
如果你不確定返回的元組一定不為nil凰狞,那么你可以返回一個(gè)可選的元組類型。
你可以通過(guò)在元組類型的右括號(hào)后放置一個(gè)問(wèn)號(hào)來(lái)定義一個(gè)可選元組沛慢,例如(Int, Int)?或(String, Int, Bool)?
注意
可選元組類型如(Int, Int)?與元組包含可選類型如(Int?, Int?)是不同的.可選的元組類型赡若,整個(gè)元組是可選的,而不只是元組中的每個(gè)元素值团甲。
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
print("最小值為 \(bounds.min)逾冬,最大值為 \(bounds.max)")
}
//沒(méi)有返回值函數(shù)
func runoob(site: String) {
print(site)
}
函數(shù)參數(shù)名稱
函數(shù)參數(shù)都有一個(gè)外部參數(shù)名和一個(gè)局部參數(shù)名。
局部參數(shù)名
局部參數(shù)名在函數(shù)的實(shí)現(xiàn)內(nèi)部使用躺苦。
//以下實(shí)例中 number 為局部參數(shù)名身腻,只能在函數(shù)體內(nèi)使用。
func sample(number: Int) {
println(number)
}
外部參數(shù)名
你可以在局部參數(shù)名前指定外部參數(shù)名匹厘,中間以空格分隔嘀趟,外部參數(shù)名用于在函數(shù)調(diào)用時(shí)傳遞給函數(shù)的參數(shù)。
如下你可以定義以下兩個(gè)函數(shù)參數(shù)名并調(diào)用它:
func pow(firstArg a: Int, secondArg b: Int) -> Int {
var res = a
for _ in 1..<b {
res = res * a
}
print(res)
return res
}
pow(firstArg:5, secondArg:3)
//125
注意
如果你提供了外部參數(shù)名愈诚,那么函數(shù)在被調(diào)用時(shí)她按,必須使用外部參數(shù)名。
可變參數(shù)
可變參數(shù)可以接受零個(gè)或多個(gè)值炕柔。函數(shù)調(diào)用時(shí)酌泰,你可以用可變參數(shù)來(lái)指定函數(shù)參數(shù),其數(shù)量是不確定的匕累。
可變參數(shù)通過(guò)在變量類型名后面加入(...)的方式來(lái)定義陵刹。
func vari<N>(members: N...){
for i in members {
print(i)
}
}
vari(members: 4,3,5)
vari(members: 4.5, 3.1, 5.6)
vari(members: "Google", "Baidu", "Runoob")
常量,變量及 I/O 參數(shù)
一般默認(rèn)在函數(shù)中定義的參數(shù)都是常量參數(shù)哩罪,也就是這個(gè)參數(shù)你只可以查詢使用授霸,不能改變它的值。
如果想要聲明一個(gè)變量參數(shù)际插,可以在參數(shù)定義前加 關(guān)鍵字碘耳,這樣就可以改變這個(gè)參數(shù)的值了。
func getName(_ name: inout String).........
此時(shí)這個(gè) name 值可以在函數(shù)中改變框弛。
一般默認(rèn)的參數(shù)傳遞都是傳值調(diào)用的辛辨,而不是傳引用。所以傳入的參數(shù)在函數(shù)內(nèi)改變瑟枫,并不影響原來(lái)的那個(gè)參數(shù)斗搞。傳入的只是這個(gè)參數(shù)的副本。
當(dāng)傳入的參數(shù)作為輸入輸出參數(shù)時(shí)慷妙,需要在參數(shù)名前加 & 符僻焚,表示這個(gè)值可以被函數(shù)修改。 以下是實(shí)例:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var x = 1
var y = 5
swapTwoInts(&x, &y)
print("x 現(xiàn)在的值 \(x), y 現(xiàn)在的值 \(y)")
//x 現(xiàn)在的值 5, y 現(xiàn)在的值 1
函數(shù)使用
在 Swift 中膝擂,使用函數(shù)類型就像使用其他類型一樣虑啤。例如隙弛,你可以定義一個(gè)類型為函數(shù)的常量或變量,并將適當(dāng)?shù)暮瘮?shù)賦值給它:
func sum(a: Int, b: Int) -> Int {
return a + b
}
var addition: (Int, Int) -> Int = sum
print("輸出結(jié)果: \(addition(40, 89))")
//輸出結(jié)果: 129
解析:
"定義一個(gè)叫做 addition 的變量狞山,參數(shù)與返回值類型均是 Int 全闷,并讓這個(gè)新變量指向 sum 函數(shù)"。
sum 和 addition 有同樣的類型萍启,所以以上操作是合法的总珠。
現(xiàn)在,你可以用 addition 來(lái)調(diào)用被賦值的函數(shù)了:
函數(shù)類型作為參數(shù)類型勘纯、函數(shù)類型作為返回類型
func sum(a: Int, b: Int) -> Int {
return a + b
}
func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
print("輸出結(jié)果: \(addition(a, b))")
}
another(addition: sum, a: 10, b: 20)
//輸出結(jié)果: 30
函數(shù)嵌套
函數(shù)嵌套指的是函數(shù)內(nèi)定義一個(gè)新的函數(shù)局服,外部的函數(shù)可以調(diào)用函數(shù)內(nèi)定義的函數(shù)。
func calcDecrement(forDecrement total: Int) -> () -> Int {
var overallDecrement = 0
func decrementer() -> Int {
overallDecrement -= total
return overallDecrement
}
return decrementer
}
let decrem = calcDecrement(forDecrement: 30)
print(decrem())
//-30
高階函數(shù)
1.map
對(duì)于原始集合里的每一個(gè)元素屡律,以一個(gè)變換后的元素替換之形成一個(gè)新的集合
let numbers = [1, 2, 4, 5, 10]
print(numbers.map{ $0 * 10 })
//打印: [10, 20, 40, 50, 100]
print(numbers.map({ (value) -> String in
return String(value)
}))
// 變成字符串?dāng)?shù)組
// Swift中閉包是函數(shù)的唯一參數(shù)或是其最后一個(gè)參數(shù)時(shí)腌逢,map的()可以被省略
numbers.map { (value) -> String in
return String(value)
}
numbers.map { value in String(value)}
print(numbers.map{ String($0)})
//直接通過(guò)$0,$1,$2來(lái)順序調(diào)用閉包的參數(shù)
//以上四種方法都是等價(jià)的
還有一種應(yīng)用場(chǎng)景,就是解析可選類型的時(shí)候超埋,map和flatMap函數(shù)會(huì)讓你的代碼更加優(yōu)雅。
舉個(gè)例子佳鳖,當(dāng)解析并判斷可選類型的時(shí)候霍殴,你可能會(huì)經(jīng)過(guò)一堆if或者guard判斷,如下所示:
func loadURL(url: URL) {
print(url.absoluteString)
}
let urlStr: String? = "https://github.com/wangyanchang21"
guard let siteStr = urlStr else {
assert(false)
}
guard let url = URL(string: siteStr) else {
assert(false)
}
loadURL(url: url)
如果使用map和flatMap函數(shù)的話系吩,就會(huì)有十分優(yōu)雅的感覺(jué)来庭。
// 這行優(yōu)雅的代碼代替上面的代碼
urlStr.flatMap(URL.init).map(loadURL)
但有一點(diǎn)需要注意,這里 map替換 flatMap會(huì)報(bào)錯(cuò), 原因在于 flatMap閉包可以返回 nil, 而 map閉包不可以穿挨。就如下面的代碼編譯不會(huì)通過(guò):
// compile error
// urlStr.map(URL.init).map(loadURL)
2.flatMap
對(duì)于元素是集合的集合月弛,可以得到單級(jí)的集合
let arrayNumbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9 ]]
print(arrayNumbers.flatMap{ $0 })
//打印: [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(arrayNumbers.flatMap{ $0.map{ $0 * 10} })
//打印: [10, 20, 30, 40, 50, 60, 70, 80, 90]
但是不是所有的首層元素都可以降維得到單級(jí)集合
1.第一種情況,解析首層元素科盛,若有nil則過(guò)濾帽衙,就不會(huì)降維
let optLatticeNumbers = [[1, Optional(2), 3], [3, nil, 5], nil]
// 解析首層元素, 若有nil則過(guò)濾, 就不會(huì)降維
let flatMapArr2 = optLatticeNumbers.flatMap { $0 }
// [[1, 2, 3], [3, nil, 5]]
2.解析首層元素,若沒(méi)有nil贞绵,則會(huì)降維
let latticeNumbers = [[1, Optional(2), 3], [3, nil, 5]]
// 解析首層元素, 若沒(méi)有nil, 則會(huì)降維
let flatMapArr = latticeNumbers.flatMap { $0 }
// [1, 2, 3, 3, nil, 5]
為了將過(guò)濾nil和降維兩個(gè)功能于區(qū)分開(kāi)厉萝,swift4.1開(kāi)始,就只保留了降維的flatMap函數(shù)榨崩,并棄用了過(guò)濾nil的flatMap函數(shù)谴垫,又用開(kāi)放的新函數(shù)compactMap來(lái)替代棄用的函數(shù)。
所以母蛛,當(dāng)需要過(guò)濾nil的時(shí)候翩剪,請(qǐng)使用compactMap函數(shù);當(dāng)需要進(jìn)行降維時(shí)彩郊,請(qǐng)使用flatMap函數(shù)前弯。這也就是flatMap和compactMap之間的區(qū)別蚪缀。
3.compactMap
過(guò)濾空值
let names: [String?] = ["zhangsan", nil, "lisi", "wangwu", nil, "zhaoliu"]
print(names.count)
// 6
print(names.map{ $0?.count })
//[Optional(8), nil, Optional(4), Optional(6), nil, Optional(7)]
print(names.compactMap{ $0 })
//打印: ["zhangsan", "lisi", "wangwu", "zhaoliu"],過(guò)濾了空值
print(names.compactMap{ $0?.count })
//打印不是空值的字符串的個(gè)數(shù)
// [8, 4, 6, 7]
注意??:可選類型的 map作用是對(duì)可選類型進(jìn)行解包操作,若有值則進(jìn)入閉包博杖,并返回一個(gè) Optional類型椿胯;若為nil,則直接返回當(dāng)前可選類型的nil剃根。
4.filter
對(duì)于原始集合里的每一個(gè)元素哩盲,通過(guò)判定來(lái)將其丟棄或者放進(jìn)新集合
let numbers = [1, 2, 4, 5, 10]
print(numbers.filter{$0 > 4})
//打印: [5, 10]
5.reduce
對(duì)于原始集合里的每一個(gè)元素,作用于當(dāng)前累積的結(jié)果上
let numbers = [1, 2, 4, 5, 10]
print(numbers.reduce(100, { $0 + $1 }))
//打印: 122
// 100 是初始值, 將所有數(shù)相加: 100 + 1 + 2 + 4 + 5 + 10 = 122
6.sort函數(shù)
對(duì)原集合進(jìn)行給定條件排序狈醉。
無(wú)返回值廉油,直接修改原集合,所以這個(gè)集合應(yīng)該是可變類型的苗傅。
var numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
numbers.sort { a, b in
return a < b
}
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
另外抒线,系統(tǒng)還定義了一個(gè)sort()函數(shù),即對(duì)集合進(jìn)行升序排序的函數(shù)渣慕。但這個(gè)函數(shù)并不是上面函數(shù)不傳入缺省值的情況嘶炭,而是另外一個(gè)函數(shù)。
var numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
numbers.sort()
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
7.sorted函數(shù)
sorted函數(shù)與sort函數(shù)對(duì)應(yīng)逊桦。
將集合進(jìn)行給定條件排序眨猎,返回一個(gè)新的集合,不修改原集合强经。
let sortedArr = numbers.sorted { a, b in
return a > b
}
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
// sorted()函數(shù)
let sortedArr2 = numbers.sorted()
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 閉包簡(jiǎn)寫(xiě)
let sortedArr3 = sortedArr2.sorted(by: >)
// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
8.prefix函數(shù)
正向取滿足條件的元素睡陪,進(jìn)行新集合創(chuàng)建。一旦出現(xiàn)不滿足條件的元素匿情,則跳出循環(huán)兰迫,不再執(zhí)行。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let prefixArr = numbers.prefix { $0 < 10 }
// [7, 6]
prefix相關(guān)函數(shù):
: 正向取元素創(chuàng)建數(shù)組, 包含小于指定index的元素
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let prefixUpToArr = numbers.prefix(upTo: 5)
// [7, 6, 10, 9, 8]
:正向取元素創(chuàng)建數(shù)組, 包含小于等于指定index的元素
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let prefixThroughArr = numbers.prefix(through: 2)
// [7, 6, 10]
: 正向取元素創(chuàng)建數(shù)組, 包含指定的元素個(gè)數(shù)
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let prefixMaxLengthArr = numbers.prefix(6)
// [7, 6, 10, 9, 8, 1]
9.drop函數(shù)
與prefix函數(shù)對(duì)應(yīng)炬称。正向跳過(guò)滿足條件的元素汁果,進(jìn)行新集合創(chuàng)建。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let dropArr = numbers.drop { $0 < 10 }
// [10, 9, 8, 1, 2, 3, 4, 5]
drop相關(guān)函數(shù):
: 正向跳過(guò)元素創(chuàng)建數(shù)組, 跳過(guò)指定元素個(gè)數(shù), 缺省值為1
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let dropFirstArr = numbers.dropFirst(3)
// [9, 8, 1, 2, 3, 4, 5]
:返向跳過(guò)元素創(chuàng)建數(shù)組, 跳過(guò)指定元素個(gè)數(shù), 缺省值為1
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let dropLastArr = numbers.dropLast(5)
// [7, 6, 10, 9, 8]
10.first函數(shù)
正向找出第一個(gè)滿足條件的元素转砖。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let first = numbers.first { $0 < 7 }
// 6
11.last函數(shù)
與first函數(shù)對(duì)應(yīng)须鼎。反向找出第一個(gè)滿足條件的元素。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let last = numbers.last { $0 > 5 }
// 8
12.firstIndex函數(shù)
正向找出第一個(gè)滿足條件的元素下標(biāo)府蔗。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let firstIndex = numbers.firstIndex { $0 < 7 }
// 1
13.lastIndex函數(shù)
反向找出第一個(gè)滿足條件的元素下標(biāo)晋控。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let lastIndex = numbers.lastIndex { $0 > 5 }
// 4
14.partition函數(shù)()(不常用)
按照條件進(jìn)行重新排序,不滿足條件的元素在集合前半部分姓赤,滿足條件的元素后半部分赡译,但不是完整的升序或者降序排列。
返回值為排序完成后集合中第一個(gè)滿足條件的元素下標(biāo)不铆。
var partitionNumbers = [20, 50, 30, 10, 40, 20, 60]
let pIndex = partitionNumbers.partition { $0 > 30 }
// partitionNumbers = [20, 20, 30, 10, 40, 50, 60]
// pIndex = 4
15.min函數(shù)
按條件排序后取最小元素蝌焚。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let min = numbers.min { $0 % 5 < $1 % 5 }
// 10
min()函數(shù)裹唆,自然升序取最小。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let minDefault = numbers.min()
// 1
16.max函數(shù)
按條件排序后取最大元素只洒。
let maxDictionary = ["aKey": 33, "bKey": 66, "cKey": 99]
let max = maxDictionary.max { $0.value < $1.value }
// (key "cKey", value 99)
max()函數(shù)许帐,自然升序取最大。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
let maxDefault = numbers.max()
// 10
17.removeAll函數(shù)
移除原集合中所有滿足條件的元素毕谴。
無(wú)返回值成畦,直接修改原集合,所以這個(gè)集合應(yīng)該是可變類型的涝开。
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
var removeArr = numbers
removeArr.removeAll { $0 > 6 }
// [6, 1, 2, 3, 4, 5]
18.集合遍歷
let numbers = [7, 6, 10, 9, 8, 1, 2, 3, 4, 5]
//forEach函數(shù):
numbers.forEach { num in
print(num)
}
//for-in函數(shù):
for num in numbers where num < 5 {
print(num)
}
//與enumerated()函數(shù)配合使用:
for (index, num) in numbers.enumerated() {
print("\(index)-\(num)")
}
19.shuffled函數(shù)
shuffled函數(shù)循帐,打亂集合中元素的的順序。
let ascendingNumbers = 0...9
let shuffledArr = ascendingNumbers.shuffled()
// [3, 9, 2, 6, 4, 5, 0, 1, 7, 8]
20.split和joined函數(shù)
split函數(shù)舀武,字符串的函數(shù)拄养,按條件分割字符串,為子字符串創(chuàng)建集合银舱。與Objective-C中的componentsSeparatedByString:方法類似瘪匿。
let line = "123Hi!123I'm123a123coder.123"
let splitArr = line.split { $0.isNumber }
// ["Hi!", "I'm", "a", "coder."]
// 也可指定字符
let splitArr2 = line.split(separator: "1")
// ["23Hi!", "23I'm", "23a", "23coder.", "23"]
joined函數(shù),數(shù)組元素連接指定字符拼接成一個(gè)字符串寻馏。與Objective-C中的componentsJoinedByString:方法類似柿顶。
let joined = splitArr.joined(separator: "_")
// "Hi!_I'm_a_coder."
// 也可以只傳入字符
let joined2 = splitArr2.joined(separator: "#")
// "23Hi!#23I'm#23a#23coder.#23"
21.zip函數(shù)
將兩個(gè)數(shù)組合并為一個(gè)元組組成的數(shù)組。
let titles = ["aaa", "bbb", "ccc"]
let numbers = [111, 222, 333]
let zipA = zip(titles, numbers)
for (title, num) in zipA {
print("\(title)-\(num)")
}
//aaa-111
//bbb-222
//ccc-333
內(nèi)聯(lián)函數(shù)(Inline Function)
如果開(kāi)啟了編譯器優(yōu)化操软,編譯器會(huì)自動(dòng)將某些函數(shù)變成內(nèi)聯(lián)函數(shù)(將函數(shù)調(diào)用展開(kāi)成函數(shù)體),我們可以看到 Release 模式默認(rèn)開(kāi)啟優(yōu)化宪祥,并且是按照速度去優(yōu)化:
比如我們有一個(gè)函數(shù)聂薪,那么一旦調(diào)用 test() 這個(gè)函數(shù),系統(tǒng)就會(huì)為這個(gè)函數(shù)分配椈妊颍空間藏澳,并且在棧空間進(jìn)行分配局部變量的操作耀找,函數(shù)執(zhí)行完之后會(huì)對(duì)函數(shù)椣栌疲空間進(jìn)行回收:
func test() {
print("test")
}
test()
我們思考一下,test() 這個(gè)函數(shù)里面的代碼非常少野芒,僅僅做一件事情打印蓄愁,那么我們直接把 test() 函數(shù)里這行代碼拿出來(lái),這樣性能不就更好嗎狞悲?其實(shí)內(nèi)聯(lián)做的操作就是這樣撮抓,將函數(shù)調(diào)用展開(kāi)成函數(shù)體代碼,這樣就減少了函數(shù)的調(diào)用開(kāi)銷摇锋,不必再開(kāi)辟回收函數(shù)的椀ふ空間了站超。展開(kāi)后代碼如下:
print("test")
接下來(lái)我們運(yùn)行看一下匯編代碼,首先在第76行代碼打一個(gè)斷點(diǎn)乖酬,然后打開(kāi)顯示反匯編選項(xiàng)(Debug -> Debug Workflow -> Always show Disassembly):
1死相、首先編譯器未開(kāi)啟優(yōu)化的情況:
0x10b294a65 <+5989>: callq 0x10b2956b0 ; test() -> () at ViewController.swift:73
我們發(fā)現(xiàn)有一個(gè) callq 0x10b2956b0 的操作,這句匯編代碼的意思就是調(diào)用 test() 函數(shù)咬像,所以未開(kāi)啟優(yōu)化的情況下沒(méi)有進(jìn)行內(nèi)聯(lián)操作算撮。
2、然后我們打開(kāi)編譯器優(yōu)化選項(xiàng):
我們?cè)?test() 函數(shù)調(diào)用的地方第76行設(shè)置斷點(diǎn)施掏,然后運(yùn)行钮惠,我們發(fā)現(xiàn) test() 函數(shù)沒(méi)有執(zhí)行,但是 “test” 字符串被打印出來(lái)了:
然后我們把斷點(diǎn)設(shè)置到第 74 行七芭,運(yùn)行查看匯編代碼
0x10ae951cf <+1871>: callq 0x10ae96e1a ; symbol stub for: Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> ()
我們看匯編可以發(fā)現(xiàn)素挽,print(“test”)代碼被直接放到 main 函數(shù)當(dāng)中,也就是編譯器幫我們做了內(nèi)聯(lián)操作狸驳。
但是有一些函數(shù)是不會(huì)被內(nèi)聯(lián):
1预明、函數(shù)體比較長(zhǎng)的函數(shù)不會(huì)被內(nèi)聯(lián)(如果函數(shù)體比較長(zhǎng),函數(shù)被調(diào)用次數(shù)也非常多耙箍,進(jìn)行內(nèi)聯(lián)操作生成的匯編代碼會(huì)非常多撰糠,也就是機(jī)器碼會(huì)變多,最終代碼體積變大安裝包變大)辩昆;
2阅酪、遞歸調(diào)用不會(huì)被內(nèi)聯(lián);
3汁针、包含動(dòng)態(tài)派發(fā)(類似Oc動(dòng)態(tài)綁定)的函數(shù)不會(huì)被內(nèi)聯(lián)术辐;
我們也可以使用@online手動(dòng)關(guān)閉/開(kāi)啟內(nèi)聯(lián)優(yōu)化的:
1、下面的函數(shù)永遠(yuǎn)不會(huì)被內(nèi)聯(lián)(即使開(kāi)啟了編譯器優(yōu)化):
@inline(never) func test() {
print("test")
}
2施无、開(kāi)啟編譯器優(yōu)化后辉词,即使代碼很長(zhǎng)也會(huì)被內(nèi)聯(lián)(遞歸調(diào)用,動(dòng)態(tài)派發(fā)的函數(shù)除外猾骡;在 release 模式下瑞躺,編譯器已經(jīng)開(kāi)啟優(yōu)化,會(huì)自動(dòng)決定哪些函數(shù)需要內(nèi)聯(lián)兴想,因此沒(méi)必要使用 @inline):
@inline(__always) func test() {
print("test")
}