美文网首页
2018-03-21

2018-03-21

作者: Toki_Han | 来源:发表于2018-03-22 12:53 被阅读8次

    从OC—Block到Swift—Closure

    写在前面

    阅读别人的代码,特别是一些被广泛认可的开源项目的源码,是快速提升自己能力的重要途径。由于个人编程风格的问题,有的大神写的代码就比较晦涩难懂,而且跳跃性很强,经常以跟不上ta的思路而宣告GG。对于我自己来说,我是比较不喜欢阅读Block/Closure特别多的代码的,用着很舒心,读着很糟心。。。
    应该有很多(?)和我一样被无数Block或者闭包导致阅读过程中出现不安感的同学,在重新查阅了一些之前的笔记和大神们的资料后,斗胆在这里做一个总结,希望能为读到这里的同学们提供些许的念头通达。
    篇幅略长,尽量不赘述,前面是block,中间是closure,最后一些tips,请选择性观看。

    利益相关

    本文原创,其中有引用别人帖子/博客/回答/etc, 参考内容较多不一一列举,如果您发现有侵权行为或者在意没有注明引用,请@龙傲天联系我等我看到邮件再说 我会在第一时间更正。
    时刻保持您的谨慎与怀疑,因为我说的并不是真理。
    本文不保留任何权益,开心就好。

    概述

    Block(代码块)是苹果在iOS4开始引入的对C语言的扩展,是一种特殊的数据类型。它本身封装了一段代码并将这段代码当做变量,通过block()的方式进行回调。
    Closure(闭包)是Swift在吸收众家之长的基础上的特性之一,是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。

    这里做个简单介绍:

    Block的功能:

    1. 定义变量
    2. 作为参数
    3. 作为返回值
    4. 保存一段代码,在需要的时候调用

    Closure的功能:

    Swift中的闭包使用情况远比Objective-C中的多,以至于闭包就是Swift的基本特性之一,和String/Array是一样的使用频率。
    Closure的功能大于等于Block的功能,并有更多的优化。

    ::注:::Closure != Block,即闭包不是Block的Swift版。

    block的声明和赋值

    相信很多人(也许只有我)很难在不参考任何资料或者在编辑器的支持下正确的定义一个block,这时推荐Xcode自带的代码块来声明它:

    // block声明
    返回值类型(^block名称)(参数列表)
    // block赋值
    Block变量 = ^(参数列表){函数体};
    
    // block声明同时赋值
    返回值类型(^block名称)(参数类型) = ^(参数列表) {
        内部的实现方法 / 参数处理 / 想要在别处调用而保存的代码
        };
    

    光说不练假把式,现在我们来写一个block让它来”HelloWorld”:

    // 可以新建一个工程,然后在 viewDidLoad 中进行简单测试,开始吧
    
    // 声明一个无返回值,参数为两个字符串对象,叫做myBlock的Block
    void(^myBlock)(NSString *a, NSString *b);
    // 形参变量名称可以省略,只留有变量类型即可(这个不是必要操作,但是要知道可以这样写)
    void(^myBlock)(NSString *, NSString *);
    
    // 给myBlock赋值
    myBlock = ^(NSString *a, NSString *b) {
            NSLog(@"%@ %@",a,b);
        };
    
    // 调用myBlock
    myBlock(@"hello",@"world");
    
    // 控制台输出结果
    "hello world"
    

    更为复杂的block也无非就是在这个基础上改变参数列表,增加函数体内的方法。Is it easy?

    注: block的声明与赋值只是保存了一段代码段,必须调用才能执行内部代码

    对于block的底层原理在这里不做探究, 因为其实我也没研究懂 因为本文重点是面向实际使用过程的,有兴趣的同学可以自行查询。
    传送门: block源码下载
    唐巧—谈Objective-C block的实现

    block特性

    • block被Objective-C看成是对象来处理
    • block对于外部变量默认是只读属性
    • block的代码是内联的,效率高于函数调用
    • block的声明与赋值只是保存了一段代码段,必须调用才能执行内部代码

    使用typedef定义Block类型

    在实际使用Block的过程中,我们可能需要重复地声明多个相同返回值,相同参数列表的Block变量,如果总是重复地编写一长串代码来声明变量会非常繁琐,所以我们可以使用typedef来定义Block类型(还记得之前我们的myBlock吗,现在把它定义成一个类型):

        // 将下面这个接受两个NSString参数,返回为空的block类型定义为名字为MyBlock的类型
        typedef void(^MyBlock)(NSString *, NSString *);
        // 使用的时候指定要使用MyBlock类型的,新建一个该类型的block对象,并定义它的工作内容
        MyBlock myNewBlock = ^(NSString *a, NSString *b) {
            NSLog(@"%@ %@",a,b);
        };
        // 让block开始工作
        myNewBlock(@"hello",@"myNewBlock");
          // 输出结果
          "hello myNewBlock"
    
          // 再次创建一个MyBlock类型的对象,并给它定义与之前不同的工作内容
        MyBlock anotherBlock = ^(NSString *str1, NSString *str2) {
            NSLog(@"only print str2: %@",str2);
        };
        // 让block开始工作
        anotherBlock(@"hello",@"world");
          // 输出结果
        "only print str2: world"
    

    Block作为函数参数

    之前的情形是直接调用block,让它执行自己内部封装的方法,更多的时候是将block当做参数传递并进行操作的,继续我们的例子:

    相关文章

      网友评论

          本文标题:2018-03-21

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