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)")
            })
        }

        // 耗时操作 {number = 3, name = (null)}
        // 主线程 {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]

你可能感兴趣的:(Swift基础-04(函数 闭包))