1.Swift中函數(shù)的使用
- 函數(shù)的定義
/// 函數(shù)格式,格式 函數(shù)名(形參列表) -> 返回值
func demo(x: Int, y: Int) -> Int {
return x + y
}
// print(demo(x: 2, y: 3))
- 外部參數(shù)
// 外部參數(shù)
/// 外部參數(shù)就是在形參前面添加一個(gè)名字
/// 外部參數(shù)不會(huì)影響內(nèi)部的細(xì)節(jié)
/// 外部參數(shù)會(huì)讓外部調(diào)用方看起來(lái)更加的直觀
func demo1(num1 x: Int,num1 y: Int) -> Int {
return x + y
}
// print(demo1(num1: 2, num1: 3))
- _的使用
// 外部參數(shù)
/// _ 外部參數(shù)如果使用 _ 在外部調(diào)用函數(shù)時(shí)會(huì)忽略形參的值
/// _ 在Swift中 就是可以忽略任意不感興趣的值
func demo2(_ x: Int, _ y: Int) -> Int {
return x + y
}
// print(demo2(2, 3));
- 常見(jiàn)的 "_" 在for循環(huán)中
/// Immutable value 'i' was never used; consider replacing with '_' or removing it
/// i 從來(lái)沒(méi)有用到 建議使用 _ 替代
func demo3() {
for i in 0...10 {
print("洋蔥數(shù)學(xué)")
}
for _ in 0...10 {
print("洋蔥數(shù)學(xué)")
}
}
- 函數(shù)的默認(rèn)值
// 函數(shù)的默認(rèn)值
// 通過(guò)給參數(shù)設(shè)置默認(rèn)值掉冶,在調(diào)用的時(shí)候,可以任意組合參數(shù)凌蔬,如果不指定莺掠,就是用默認(rèn)值
// OC中需要定義很多的方法衫嵌,以及實(shí)現(xiàn)方法,最終調(diào)用包含所有參數(shù)的那個(gè)方法
// OC中可以看SDWebImage分類(lèi) 為圖片添加分類(lèi)
func demo4(x: Int = 1, y: Int = 2) -> Int {
return x + y
}
print(demo4())
print(demo4(x: 10, y: 20))
print(demo4(x: 10))
print(demo4(y: 20))
- 無(wú)返回值的函數(shù)的用
// 無(wú)返回值的函數(shù)值
/**
三種方式
->直接省略
->()
->Void
*/
func demo5() { // func demo5() - () 或者 func demo7() -> Void
print("哈哈")
}
- 返回多個(gè)值的函數(shù)
/// “使用元組來(lái)讓一個(gè)函數(shù)返回多個(gè)值彻秆。該元組的元素可以用名稱(chēng)或數(shù)字來(lái)表示楔绞。”
func demo(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
// 調(diào)用 print(demo(scores: [1,4,7]))
// 輸出 (min: 1, max: 7, sum: 12)
- 可變參數(shù)的函數(shù)
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
// sumOf()
// sumOf(numbers: 42, 597, 12)
- 函數(shù)作為返回值的情況
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
// var increment = makeIncrementer()
// increment(7)
- 函數(shù)作為參數(shù)的情況
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
// var numbers = [20, 19, 7, 12]
// hasAnyMatches(list: numbers, condition: lessThanTen)
- 輸入輸出參數(shù)
數(shù)參數(shù)默認(rèn)是常量唇兑。試圖在函數(shù)體中更改參數(shù)值將會(huì)導(dǎo)致編譯錯(cuò)誤(compile-time error)酒朵。這意味著你不能錯(cuò)誤地更改參數(shù)值。如果你想要一個(gè)函數(shù)可以修改參數(shù)的值扎附,并且想要在這些修改在函數(shù)調(diào)用結(jié)束后仍然存在蔫耽,那么就應(yīng)該把這個(gè)參數(shù)定義為輸入輸出參數(shù)(In-Out Parameters)。
定義一個(gè)輸入輸出參數(shù)時(shí)留夜,在參數(shù)定義前加inout
關(guān)鍵字匙铡。一個(gè)輸入輸出參數(shù)有傳入函數(shù)的值,這個(gè)值被函數(shù)修改碍粥,然后被傳出函數(shù)鳖眼,替換原來(lái)的值。
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoInts(::) 函數(shù)簡(jiǎn)單地交換 a 與 b 的值嚼摩。該函數(shù)先將 a 的值存到一個(gè)臨時(shí)常量 temporaryA 中钦讳,然后將 b 的值賦給 a,最后將 temporaryA 賦值給 b枕面。
你可以用兩個(gè) Int 型的變量來(lái)調(diào)用 swapTwoInts(::)愿卒。需要注意的是,someInt 和 anotherInt 在傳入 swapTwoInts(::) 函數(shù)前膊畴,都加了 & 的前綴:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 打印 "someInt is now 107, and anotherInt is now 3
2.Swift中閉包
- 使用常量記錄函數(shù)
// 使用常量記錄函數(shù)
func demo() {
print(sum(x: 10, y: 20));
// f 的類(lèi)型 (Int, Int) -> Int
let f = sum
print(f(30, 40))
}
func sum(x: Int, y: Int) -> Int {
return x + y
}
- 簡(jiǎn)單的閉包
func demo2() {
// 沒(méi)有參數(shù)和返回值掘猿,可以省略病游,連 in 都可以省略
// b1: () -> ()
let b1 = {
print("hello")
}
// 執(zhí)行閉包
b1()
// 在OC中的寫(xiě)法,可以對(duì)比一下
/**
void (^b1) = ^{
NSLog("hello")
};
b1()
*/
}
- 帶參數(shù)的閉包
/**
閉包中唇跨,參數(shù) 返回值 實(shí)現(xiàn)代碼都寫(xiě)在 {} 中
需要使用一個(gè)關(guān)鍵字 in 來(lái)分割定義和實(shí)現(xiàn)
*/
func demo3() {
// (Int) -> Int
let b2 = { (x: Int) -> Int in
return x
}
print(b2(3))
// (Int) -> ()
let b3 = { (x: Int) -> () in
print("hello")
}
b3(3)
}
3.Swift中GCD
與OC中的GCD使用姿勢(shì)不太一樣,但是執(zhí)行步驟是一樣的衬衬,都是先創(chuàng)建隊(duì)列买猖,然后執(zhí)行任務(wù)
func loadData() -> () {
// 講任務(wù)添加到隊(duì)列,指定執(zhí)行任務(wù)的函數(shù)
/**
OC 匯總的使用
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
});
});
*/
DispatchQueue.global().async {
print("耗時(shí)操作 \(Thread.current)")
DispatchQueue.main.async(execute: {
print("主線程 \(Thread.current)")
})
}
// 耗時(shí)操作 <NSThread: 0x6180000646c0>{number = 3, name = (null)}
// 主線程 <NSThread: 0x608000065380>{number = 1, name = main}
}
4.通過(guò)閉包傳遞值
// 閉包作為參數(shù)滋尉,閉包一般都不寫(xiě)參數(shù)名
func loadData2(compeletion: (Int, Int) ->()) {
compeletion(3, 4)
}
func loadData22(compeletion: (_ x: Int, _ y: Int) ->()) {
compeletion(3, 4)
}
// 調(diào)用姿勢(shì)
loadData2 { (a, b) in
print("\(a) \(b)")
}
loadData22 { (a) in
print("\(a) ")
}
func loadData3(compeletion: (_ array: [String]) -> ()) -> (){
let arr: [String] = ["1", "2", "3"]
compeletion(arr)
}
func loadData33(compeletion: ([String]) -> ()) {
let arr: [String] = ["1", "2", "3"]
compeletion(arr)
}
// 調(diào)用姿勢(shì)
loadData3 { (arr) in
print(arr)
}
func loadData4(x: Int, completetion: (_ array: [String]) ->()) {
let arr: [String] = ["1", "2", "3"]
completetion(arr)
}
func loadData44(x: Int, completetion: ([String]) ->()) {
let arr: [String] = ["1", "2", "3"]
completetion(arr)
}
// 調(diào)用姿勢(shì)
loadData4(x: 3) { (array) in
print("3 --- \(array)")
}
5.尾隨閉包
// 如果函數(shù)的最后一個(gè)參數(shù)是閉包玉控,函數(shù)就可以提前結(jié)束,最后一個(gè)參數(shù)直接使用{}包裝閉包的代碼
// 省略了 compeletion 這個(gè)閉包
loadData3 { (arr) in
print(arr)
}
loadData3(compeletion: { (array) -> () in
print(array)
})
loadData4(x: 3) { (array) in
print("3 --- \(array)")
}
6.尾隨閉包在OC上的坑
比如我們?cè)贠C中經(jīng)常寫(xiě)這樣的代碼狮惜,
UILabel *label = [[UILabel alloc] init];
{
UILabel *label = [[UILabel alloc] init];
}
在swift中尾隨閉包的問(wèn)題
let l = UILabel()
// 下面的這句話就會(huì)包這個(gè)錯(cuò)高诺,Extra argument in call
// 就是由于尾隨閉包 默認(rèn)會(huì)把最后一個(gè) {} 作為尾隨閉包的結(jié)束
view.addSubview(l)
{
let l = UILabel()
view.addSubview(l)
}
7. @escaping 的使用
如果這個(gè)閉包是在這個(gè)函數(shù)結(jié)束前內(nèi)被調(diào)用碌识,就是非逃逸的即noescape。當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中虱而,但是這個(gè)閉包在函數(shù)返回之后才被執(zhí)行筏餐,我們稱(chēng)該閉包從函數(shù)中逃逸。當(dāng)你定義接受閉包作為參數(shù)的函數(shù)時(shí)牡拇,你可以在參數(shù)名之前標(biāo)注 @escaping魁瞪,用來(lái)指明這個(gè)閉包是允許“逃逸”出這個(gè)函數(shù)的。
一種能使閉包“逃逸”出函數(shù)的方法是惠呼,將這個(gè)閉包保存在一個(gè)函數(shù)外部定義的變量中导俘。舉個(gè)例子,很多啟動(dòng)異步操作的函數(shù)接受一個(gè)閉包參數(shù)作為 completion handler剔蹋。這類(lèi)函數(shù)會(huì)在異步操作開(kāi)始之后立刻返回旅薄,但是閉包直到異步操作結(jié)束后才會(huì)被調(diào)用。在這種情況下泣崩,閉包需要“逃逸”出函數(shù)赋秀,因?yàn)殚]包需要在函數(shù)返回之后被調(diào)用。
在swift3中做出了一個(gè)對(duì)調(diào)的改變:所有的閉包都默認(rèn)為非逃逸閉包律想,不再需要@noescape猎莲;
// 如果是逃逸閉包,就用@escaping表示技即。比如下面的一段代碼著洼,callBack在從子線程切換到主線程中,
// 調(diào)用的地方超出的函數(shù)的范圍而叼,所以是逃逸閉包身笤。
func demo4(complatetion: @escaping ([String]) -> ()) {
DispatchQueue.global().async {
let arr = ["1", "2" ,"3"]
DispatchQueue.main.async(execute: {
complatetion(arr)
})
}
}
8. Swift閉包中$0 和 $1的理解
Swift 自動(dòng)對(duì)行內(nèi)閉包提供簡(jiǎn)寫(xiě)實(shí)際參數(shù)名,你也可以通過(guò) $0 , $1 , $2 等名字來(lái)引用閉包的實(shí)際參數(shù)值葵陵。
如果你在閉包表達(dá)式中使用這些簡(jiǎn)寫(xiě)實(shí)際參數(shù)名液荸,那么你可以在閉包的實(shí)際參數(shù)列表中忽略對(duì)其的定義,并且簡(jiǎn)寫(xiě)實(shí)際參數(shù)名的數(shù)字和類(lèi)型將會(huì)從期望的函數(shù)類(lèi)型中推斷出來(lái)脱篙。 in 關(guān)鍵字也能被省略娇钱,因?yàn)殚]包表達(dá)式完全由它的函數(shù)體組成,舉個(gè)栗子:
let numbers = [3,2,4,1,5,7,6];
var sortedNumbers = numbers.sorted(by:{$0 < $1});
print(sortedNumbers);//輸出為:[1, 2, 3, 4, 5, 6, 7]
sortedNumbers = numbers.sorted(by:{$1 < $0});
print(sortedNumbers);//輸出為:[7, 6, 5, 4, 3, 2, 1]