Swift5 函数与闭包

作者: 一粒咸瓜子 | 来源:发表于2020-09-12 21:06 被阅读0次

    函数

    是一种特殊的闭包

    // 无参无返回值的三种写法
    func a() -> Void { ... }
    func a() -> () { ... } 
    func a() { ... }  //最简
    
    
    // 有参数无返回值
    func square(a: Int, b: Int) -> Int { return a * b }
    // 有参数有返回值
    func square(a: Int, b: Int) { ... } //最简
    

    内部函数

    在函数体内部定义的函数,调用需在声明后

    func result() {
        func sum(a: Int, b: Int) -> Int {
            return a + b
        }
        //在内部函数声明的下面调用
        print(sum(a: 20, b: 80))
    }
    

    外部参数及忽略

    提供外部参数能增强函数的可读性,同时也能够让函数在内部使用参数更加简单
    忽略外部参数用 “_” 表示

    // frist/second表示外部参数,a标识函数的内部参数只能够在函数的内部使用
    func sum(first a: Int, second b: Int) -> Int {
        return a + b
    }
    sum(first: 10, second: 20);
    
    // 忽略外部参数 “_”
    func sum(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
    sum(10, 20);
    

    函数小技巧

    多返回值:元组类型

    oc 中使用输出参数实现
    使用元组来让一个函数返回多个值。该元组的元素可以用名称或数字来表示。

    func calculateStatistics(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)
    }
    //let statistics: (min: Int, max: Int, sum: Int)
    let statistics = calculateStatistics(scores:[5, 3, 100, 3, 9])
    //或者print(statistics.2) 该元组的元素可以用名称或数字来表示
    print(statistics)
    

    不确定参数

    oc 中使用 va_list 等宏实现
    参数个数可变:函数可以带有可变个数的参数,这些参数在函数内表现为数组的形式

    func nameFunc(names: String...) {
        for name in names {
            print(name, terminator: " ")
        }
    }
    nameFunc(names: "zhangsan", "lisi", "wangwu")
    // Prints "zhangsan lisi wangwu "
    

    闭包

    closure:Swift 中的 block
    闭包是一个封闭的结构: 闭包的参数,返回值、需要执行的代码片段 都应该在闭包的内部

    函数和闭包都是引用类型:无论你将函数或闭包赋值给一个常量还是变量,你实际上都是将常量或变量的值设置为对应函数或闭包的引用

    // block
    void(^callback)(NSString *) = ^(NSString *str) {
        // code
    }
    
    // closure
    let closure = { (str: String) -> () in
        // code
    }
    

    写法

    一般左边不写,参数类型和返回值类型在闭包内标明即可

    • 无参无返回值
    // 完整形式 左右都有 标明闭包类型
    let closure:() -> () = { () -> () in  
        print("最简单的闭包完整形式")
    }
    
    // 简化:左边不写,右边标明闭包类型,返回值为空时,写()和 Void 一样 
    let closure = { () -> Void in
        print("返回值为空时")
    }
    
    // 最简形式
    let closure = {
        print("最简形式")
    }
    
    • 有参无返回值
    let closure = { (a: Int, b: Int) in
        print("\(a) + \(b) = \(a+b)")
    }
    
    • 有参有返回值
    let closure = { (a: Int, b: Int) -> (String) in
        return "\(a+b)"
    }
    

    尾随闭包

    当函数的最后一个参数是闭包的时候,函数的参数的 '()' 可提前关闭。
    如果函数只有闭包这一个参数, '()' 可以省略,如果闭包类型是无参无返回值,"() -> () in" 也可以省略。

    是在调用函数的时候可以省略,而不是声明的时候

    bug:如果写出来的闭包函数报错,可以在声明的时候把返回值写上,调用成功后再删除

    func loadData(name: String, completed: (Int) -> ()) {
        completed((name as NSString).length)
    }
    
    loadData(name: "abc") { (count) in
        print("name's count = " + "\(count)")
    }
    //Prints "name's count = 3"
    
    func cFunc(closure: () -> ()) {
        closure()
    }
    cFunc {             
        // code
    }
    

    @escaping

    逃逸闭包:当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping,⽤来指明这个闭包是允许“逃逸”出这个函数的

    @escaping:标识该闭包可以逃离当前的“语境”,写在闭包类型声明之前,闭包作为函数的参数是默认不可逃逸的。

    @escaping 语境:

    • 闭包在 async 需要逃逸、sync 不需要逃逸


    • 闭包被引用,需要逃逸。


    循环引用

    方法一:[weak self] (推荐)
    self 是可选项,如果 self 已经被释放,则为 nil

    // 类似 OC 中:__weak typeof(self) weakSelf;
    // 如果 self 已经被释放,则为 nil
    loadData { [weak self] in
        print("\(self?.view)")
    }
    

    方法二: [unowned self] (不推荐)
    self 不是可选项,如果 self 已经被释放,则出现野指针访问

    // 类似 OC 中:__unsafe_unretained typeof(self) weakSelf; 
    // 如果 self 已经被释放,则出现野指针访问
    loadData { [unowned self] in
        print("\(self.view)")
    }
    

    方法三:与 OC 类似

    weak var weakSelf = self
    loadData() {
        print("\(weakSelf?.view)")
    }
    

    网络请求试写

    func request(urlStr: String, compeletd:@escaping (Bool, Any) -> Void) {
        guard let url = URL(string: urlStr) else {
            return
        }
        DispatchQueue.global().async {
            URLSession.shared.dataTask(with: url) { (data, _, error) in
                if error != nil {
                    DispatchQueue.main.async {
                        compeletd(false, error!)
                    }
                } else {
                    let json = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
                    DispatchQueue.main.async {
                        compeletd(true, json!)
                    }
                }
            }.resume()
        }
    }
    

    相关文章

      网友评论

        本文标题:Swift5 函数与闭包

        本文链接:https://www.haomeiwen.com/subject/abtgektx.html