Swift基础-04(函数 闭包)

1.Swift中函数的使用
  • 函数的定义
  /// 函数格式,格式 函数名(形参列表) -> 返回值
    func demo(x: Int, y: Int) -> Int {
        return x + y
    }
//  print(demo(x: 2, y: 3))
  • 外部参数
    // 外部参数
    /// 外部参数就是在形参前面添加一个名字
    /// 外部参数不会影响内部的细节
    /// 外部参数会让外部调用方看起来更加的直观
    func demo1(num1 x: Int,num1 y: Int) -> Int {
        return x + y
    }
// print(demo1(num1: 2, num1: 3))
  • _的使用
    // 外部参数
    /// _ 外部参数如果使用 _ 在外部调用函数时会忽略形参的值
    /// _ 在Swift中 就是可以忽略任意不感兴趣的值
    func demo2(_ x: Int, _ y: Int) -> Int {
        return x + y
    }
//  print(demo2(2, 3));
  • 常见的 "_" 在for循环中
 /// Immutable value 'i' was never used; consider replacing with '_' or removing it
    /// i 从来没有用到 建议使用 _ 替代
    func demo3()  {
        for i in 0...10 {
            print("洋葱数学")
        }
        for _ in 0...10 {
            print("洋葱数学")
        }
    }
  • 函数的默认值
    // 函数的默认值
    // 通过给参数设置默认值,在调用的时候,可以任意组合参数,如果不指定,就是用默认值
    // OC中需要定义很多的方法,以及实现方法,最终调用包含所有参数的那个方法
    // OC中可以看SDWebImage分类 为图片添加分类
    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))
  • 无返回值的函数的用
   // 无返回值的函数值
    /**
        三种方式
        ->直接省略 
        ->()
        ->Void
     */
    func demo5() {  // func demo5() - () 或者 func demo7() -> Void
        print("哈哈")
    }
  • 返回多个值的函数
   /// “使用元组来让一个函数返回多个值。该元组的元素可以用名称或数字来表示。”
    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)
    }
// 调用 print(demo(scores: [1,4,7])) 
// 输出 (min: 1, max: 7, sum: 12)
  • 可变参数的函数
 func sumOf(numbers: Int...) -> Int {
        var sum = 0
        for number in numbers {
            sum += number
        }
        return sum
    }
//  sumOf()
//  sumOf(numbers: 42, 597, 12)
  • 函数作为返回值的情况
 func makeIncrementer() -> ((Int) -> Int) {
        func addOne(number: Int) -> Int {
            return 1 + number
        }
        return addOne
    }
  // var increment = makeIncrementer()
  // increment(7)
  • 函数作为参数的情况
    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)
  • 输入输出参数
    数参数默认是常量。试图在函数体中更改参数值将会导致编译错误(compile-time error)。这意味着你不能错误地更改参数值。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)。
    定义一个输入输出参数时,在参数定义前加inout关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

swapTwoInts(::) 函数简单地交换 a 与 b 的值。该函数先将 a 的值存到一个临时常量 temporaryA 中,然后将 b 的值赋给 a,最后将 temporaryA 赋值给 b。
你可以用两个 Int 型的变量来调用 swapTwoInts(::)。需要注意的是,someInt 和 anotherInt 在传入 swapTwoInts(::) 函数前,都加了 & 的前缀:

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中闭包
  • 使用常量记录函数
  // 使用常量记录函数
    func demo() {
        print(sum(x: 10, y: 20));
        // f 的类型  (Int, Int) -> Int
        let f = sum
        print(f(30, 40))
    }

    func sum(x: Int, y: Int) -> Int {
        return x + y
    }
  • 简单的闭包
    func demo2() {
        // 没有参数和返回值,可以省略,连 in 都可以省略
        // b1: () -> ()
        let b1 = {
            print("hello")
        }
        // 执行闭包
        b1()
        
        // 在OC中的写法,可以对比一下
        /**
         void (^b1) = ^{
            NSLog("hello")
         };
         b1()
         */
    }
  • 带参数的闭包
 /**
     闭包中,参数 返回值 实现代码都写在 {} 中
     需要使用一个关键字 in 来分割定义和实现
     */
    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使用姿势不太一样,但是执行步骤是一样的,都是先创建队列,然后执行任务

  func loadData() -> () {
        // 讲任务添加到队列,指定执行任务的函数
        /**
         OC 汇总的使用
         dispatch_async(dispatch_get_global_queue(0, 0), ^{
             dispatch_async(dispatch_get_main_queue(), ^{
             
             });
         });
         */
        
        DispatchQueue.global().async {
            print("耗时操作 \(Thread.current)")
            DispatchQueue.main.async(execute: {
                print("主线程 \(Thread.current)")
            })
        }

        // 耗时操作 <NSThread: 0x6180000646c0>{number = 3, name = (null)}
        // 主线程 <NSThread: 0x608000065380>{number = 1, name = main}
    }
4.通过闭包传递值
  // 闭包作为参数,闭包一般都不写参数名
    func loadData2(compeletion: (Int, Int) ->())  {
        compeletion(3, 4)
    }
    func loadData22(compeletion: (_ x: Int, _ y: Int) ->())  {
        compeletion(3, 4)
    }
 
   // 调用姿势
   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)
    }
      // 调用姿势
    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)
    }
    // 调用姿势
    loadData4(x: 3) { (array) in
         print("3 --- \(array)")
   }
5.尾随闭包
        // 如果函数的最后一个参数是闭包,函数就可以提前结束,最后一个参数直接使用{}包装闭包的代码
        // 省略了 compeletion 这个闭包
        loadData3 { (arr) in
            print(arr)
        }
        
        loadData3(compeletion: { (array) -> () in
            print(array)
        })
        
        loadData4(x: 3) { (array) in
            print("3 --- \(array)")
        }
6.尾随闭包在OC上的坑

比如我们在OC中经常写这样的代码,

    UILabel *label = [[UILabel alloc] init];
    {
        UILabel *label = [[UILabel alloc] init];
    }

在swift中尾随闭包的问题

  let l = UILabel()
 // 下面的这句话就会包这个错,Extra argument in call 
// 就是由于尾随闭包 默认会把最后一个 {} 作为尾随闭包的结束
 view.addSubview(l)
 {
    let l = UILabel()
    view.addSubview(l)
 }
7. @escaping 的使用

如果这个闭包是在这个函数结束前内被调用,就是非逃逸的即noescape。当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping,用来指明这个闭包是允许“逃逸”出这个函数的。
一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回,但是闭包直到异步操作结束后才会被调用。在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。
在swift3中做出了一个对调的改变:所有的闭包都默认为非逃逸闭包,不再需要@noescape;

// 如果是逃逸闭包,就用@escaping表示。比如下面的一段代码,callBack在从子线程切换到主线程中,
// 调用的地方超出的函数的范围,所以是逃逸闭包。
    func demo4(complatetion: @escaping ([String]) -> ()) {
        DispatchQueue.global().async {
             let arr = ["1", "2" ,"3"]
             DispatchQueue.main.async(execute: {
                 complatetion(arr)
             })
        }
    }
8. Swift闭包中$0 和 $1的理解

Swift 自动对行内闭包提供简写实际参数名,你也可以通过 $0 , $1 , $2 等名字来引用闭包的实际参数值。
如果你在闭包表达式中使用这些简写实际参数名,那么你可以在闭包的实际参数列表中忽略对其的定义,并且简写实际参数名的数字和类型将会从期望的函数类型中推断出来。 in 关键字也能被省略,因为闭包表达式完全由它的函数体组成,举个栗子:

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]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容