有关swift闭包的理解

前面写过一篇block的文章。swift看了看,闭包这块感觉block差不多。代码敲了敲,流程走一遍,有了一点理解。

1、闭包的简单使用

PS:还是习惯用block命名闭包

        let addBlock:(Int, Int) -> (Int) = {
            (a, b) -> Int in
            return a+b;
        }
        
        let c:Int = addBlock(10, 15);
        print(c);

如上,定义一个闭包,闭包名称是addBlock,闭包类型是:2个Int参数,返回值是Int。后面紧接着就实现了闭包。下面就是闭包的调用,用一个Int类型接收闭包的返回值。over。

这么定义闭包的格式看着眼熟不?

            let data:String = "我是网络数据---哈哈"

没错,和定义一个普通的对象一样,let 名称:类型 = 结果,
闭包就是一个函数的类型。类型就是什么参数返回神结果

比如这个闭包类型就是2个Int参数返回一个Int结果。

这就是闭包的简单使用。至于其他的书写方式,在什么情况下,啥时候省略void,省略in,省略形参啥的,这里不做讨论。万变不离其宗,都是这个格式的变形而已。

再看一个swift函数的定义和使用

//函数的声明、实现
        func stadFunc(pa:Int, pb:Int) -> Int{
            return pa + pb;
        }
        
//调用函数
        let d = stadFunc(pa: 10, pb: 3);
        print(d);

和闭包一样,同样的定义,参数、返回值、实现的大括号部分等等。
以前block的时候就说过block其实就是函数的变形,闭包同理。

如果闭包都这么简单的使用,和普通函数没啥区别,就体现不出它的价值了。

2、闭包的回调

以前block就说回调的功能,这个功能才是主要的用途,可以传递数据、发送个通知啥的。
上面说过,闭包可以看作函数,具有这个函数的类型。既然有了类型,就和普通数据一样,可以当做另外一个函数的参数。

        func textAddBlock(block:(Int, Int) -> Void, failBlock:()->Void){
            
            let resultA = 11;
            let resultB = 12;
            
            print("打印1")
            block(resultA, resultB)
        }
        
        textAddBlock(block: { (pa:Int, pb:Int) in
            
            let result = pa + pb;
            print("block结果打印\(result)")
            
        }) {
            print("failBlock打印2222")
        };

上面的代码,我定义了2个闭包,当做参数传递给另外一个函数了。
类似 func stadFunc(pa:Int, pb:Int) -> Int 函数中传了2个Int类型的参数。

既然强调了几遍闭包就是函数的概念。那么闭包使用起来和函数一样,实现和调用一个都不少。
回调的巧妙之处在于,一个函数是另一个函数的参数,闭包作为参数,就需要被另外一个函数使用,就像a:Int参数,在函数的使用部分用起来可以是return a;。闭包使用起来,就是调用它了。(参考上面代码)
实现的代码在另一个函数的调用部分,所以可以把这个函数实现部分的数据传递过来。就实现了回调。
所以回调的本质就是两个函数的声明实现代码和调用代码相互嵌套书写。

3、逃逸闭包

简单来说,就是一个闭包的调用的时候,它所在的函数实现部分已经结束了。常用于网络请求等多线程中。
比如,我写了个简单网络请求工具(什么都是假的)

import UIKit

class NetWokrTool: NSObject {

    func requestResult(successBlock:@escaping (String, Bool)->Void, failBlokc:@escaping (Bool)->Void) -> Void {
        
        DispatchQueue.global().async {
          
            sleep(2);

            let data = "我是网络数据---哈哈"
            let result:Bool = true;
            
            successBlock(data, result);
            failBlokc(result);

        };
    }
}

定义实现了一个请求的方法,其中把2个闭包作为参数,一个成功,一个失败的闭包。模拟了子线程请求。
得到了网络数据和请求结果后,通过调用闭包,把数据传递出去。

由于需要在控制器中的主线程中调用这个工具类,正常走下去,走到这个方法里,发现有了子线程,主线程不管这个,继续走,直到这个函数走完,函数的生命周期就结束了。但是函数走完了,子线程还在工作,里面的代码还没结束,导致闭包的生命周期比这个函数还长,不会在相关函数结束后释放。所以需要逃出这个函数的掌控才能工作,用@escaping标记为逃逸闭包。其实是为了内存的释放。(感觉类似block的弱引用的作用差不多)

在控制器中调用这个工具类

        let tool:NetWokrTool = NetWokrTool();
        
        tool.requestResult(successBlock: { (data, result) in
            
            print(data,result)
            
        }) { (result) in
            
            print(result);
        };

结果:


回调结果.png

最终把请求得到的数据和结果回调到了控制器中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 今天的博客算是比较基础的,还是那句话,基础这东西在什么时候都是最重要的。说到函数,只要是写过程序就肯定知道函数是怎...
    攞你命3OOO阅读 598评论 0 1
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,210评论 30 471
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,276评论 9 118
  • 86.复合 Cases 共享相同代码块的多个switch 分支 分支可以合并, 写在分支后用逗号分开。如果任何模式...
    无沣阅读 1,429评论 1 5
  • Swift 介绍 简介 Swift 语言由苹果公司在 2014 年推出,用来撰写 OS X 和 iOS 应用程序 ...
    大L君阅读 3,301评论 3 25