zoukankan      html  css  js  c++  java
  • Objective-C中的Block(闭包)

    转自http://www.cnblogs.com/ludashi/p/3903054.html?utm_source=tuicool&utm_medium=referral

            学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西。学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也支持闭包, 也就是OC中所提到的Block。 到底什么是闭包或者block呢?用大白话说就是匿名函数,也就是在函数中可以包含这函数。就是在函数中可以定义匿名函数然后在函数中调用。学习OC中的block之前也小担心一下,Block在OC中属于高级的部分,心里有又有个疑问:学起来难不难?看过Block的部分,感觉Block挺好理解的,用起来也挺顺手的,Block没我想象中的那么难理解。

            废话少说,学习一门新的编程语言是少不了代码量的支持的,所以代码是少不了的。下面就通代码来认识一下OC中的block的使用。

            Block基础部分

            1.Block的声明

                Block的定义和函数的声明差不多,就是把函数名改成(^blockName)即可。下面是block声明的代码。

                有返回值的

    1
    int (^sumBlock) (intint);

                无返回值的 

    1
    void (^myBlock)(intint);

              2.给block块赋值

               给声明好的block,赋值。block的值就是个函数体,给block块赋值有两种方式,一个在声明的时候赋值,一个是先声明在赋值。

                先声明再赋值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //代码块的声明
    void (^myBlock)(intint);
     
    //给代码块赋值
    myBlock = ^(int a, int b)
    {
        //test ++;  //报错
        NSLog(@"main_test = %d", test);
     
        //blockVar++不报错;
        blockVar ++;
        NSLog(@"blockVar = %d", blockVar);
     
        int sum = a + b;
        NSLog(@"a + b = %d", sum);
    };

                在声明的时候赋值

    1
    2
    3
    4
    5
    int (^sumBlock) (intint) = ^(int a, int b)
    {
        int sum = a + b;
        return sum;
    };

              3.调用block 

             block的使用和普通函数的使用相同,调用方法如下:

    1
    2
    //调用代码块并接收返回值
    int sum = sumBlock(20, 30);

             4.把block当做参数传入函数

    1
    2
    3
    4
    5
    6
    //把代码块作为函数参数
    void blockFunction(int (^myBlock)(intint))
    {
        int sum = myBlock(10,20);
        NSLog(@"fun_sum = %d", sum);
    }  

            5.在代码块中使用局部变量和全局变量

                在block中可以和对全局变量进行访问和修改,但对局部变量只可以访问,若想修改的话,我们可以在声明局部变量的时候加上关键字__block

                代码如下:

    1
    __block int blockVar = 0;

            Block进阶 参考博客:http://www.cnblogs.com/NarutoYq/

            下面的这些内容是参考上面的博客进一步学习的Block的内容,代码是参考这上面的博客自己写的,也就是说下面的东西算是伪原创吧。小伙伴们如果没大看懂下面的东西,请去上面的博客中进一部的了解一下block.

            1.局部变量可变对象和不可变对象在block中的引用

                下面会提供一部代码,这部分代码的功能是定义两个局部变量,一个是可变对象,一个是不可变对象,然后再定义一个Block, 在block中引用两个局部变量。上面提到了在代码块中可以引用局部变量但是不可以更改其值,除非在声明的时候加上__block关键字。

                测试代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    void blockTest1()
    {
        //定义两个变量一个是可变的一个是不可变的
        NSString *str1 = @"str1";
        NSMutableString *str2 = [NSMutableString stringWithFormat:@"str2"];
     
        //初始值
     
        NSLog(@"两个字符串的初始值和初始地址");
        NSLog(@"str1 = %@,  str1_p = %p", str1, str1);
        NSLog(@"str2 = %@,  str2_p = %p", str2, str2);
     
     
        //定义block在block中输出连个变量的值和参数
        void (^myBlock) () = ^()
        {
            NSLog(@"******************************************");
            NSLog(@"在block块中输出局部变量的可变和不可变变量");
            NSLog(@"str1 = %@,  str1_p = %p", str1, str1);
            NSLog(@"str2 = %@,  str2_p = %p", str2, str2);
        };
     
        //修改前赋值
        str1 = @"str1_update";
        [str2 appendString:@"_update"];
        NSLog(@"******************************************");
        NSLog(@"输出修改后的值和地址");
        NSLog(@"str1 = %@,  str1_p = %p", str1, str1);
        NSLog(@"str2 = %@,  str2_p = %p", str2, str2);
     
        //调用block
        myBlock();
     
        NSLog(@"******************************************");
        NSLog(@"调用block后的值和地址");
        NSLog(@"str1 = %@,  str1_p = %p", str1, str1);
        NSLog(@"str2 = %@,  str2_p = %p", str2, str2);
     
     
    }

            代码说明:给定义的各一个可变和不可变的对象一个初始值,然后在调用代码块的时候修改两个局部变量的值,然后再代码块中显示变量的值。

            运行结果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    2014-08-10 13:30:25.710 Memory[1074:303] 两个字符串的初始值和初始地址
    2014-08-10 13:30:25.711 Memory[1074:303] str1 = str1,  str1_p = 0x100005ef0
    2014-08-10 13:30:25.712 Memory[1074:303] str2 = str2,  str2_p = 0x100204330
    2014-08-10 13:30:25.712 Memory[1074:303] ******************************************
    2014-08-10 13:30:25.712 Memory[1074:303] 输出修改后的值和地址
    2014-08-10 13:30:25.713 Memory[1074:303] str1 = str1_update,  str1_p = 0x100005fd0
    2014-08-10 13:30:25.713 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330
    2014-08-10 13:30:25.713 Memory[1074:303] ******************************************
    2014-08-10 13:30:25.714 Memory[1074:303] 在block块中输出局部变量的可变和不可变变量
    2014-08-10 13:30:25.714 Memory[1074:303] str1 = str1,  str1_p = 0x100005ef0
    2014-08-10 13:30:25.714 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330
    2014-08-10 13:30:25.714 Memory[1074:303] ******************************************
    2014-08-10 13:30:25.715 Memory[1074:303] 调用block后的值和地址
    2014-08-10 13:30:25.715 Memory[1074:303] str1 = str1_update,  str1_p = 0x100005fd0
    2014-08-10 13:30:25.715 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330

             从上面的输出结果我们可以看到,在代码块中输出的不可变对象是原有的值,而不是我们改后的值,地址也是初始的地址。而对于可变对象,值是我们修改后的值,而地址使用原有的地址。如果要想block和不可变局部变量绑定的话,我们要加上_block

            还是引用上面博客中的一段话来做一下总结吧:

    1. 对值类型的修改,如果block初始化后,无法同步到block内部

    2. 对于引用类型的修改,如果block初始化后,修改指针指向,即指向另外一块内存,这样也是无法同步到block内部

    3. 对于引用类型的修改,如果block初始化后,对指针指向的内存进行修改,即NSMutableArray add 、remove操作,这样是可以用同步到block内部,但block内部同样无法修改。

         2.成员变量在block中的使用

        ​    ​成员变量在block中的使用是加上self->a使用的,所以在声明成员变量的时候加不加__block,在成员函数中的代码块中都可以访问修改;

        ​    ​代码走起:

        ​    ​interface:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @interface BlockTest : NSObject
    //声明两个成员变量一个用__block 和 不用__block修饰观察其变化
    {
        __block NSString *hasBlock;
        NSString *noBlock;
    }
     
    -(void)test;
     
    @end

        ​方法的实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    @implementation BlockTest
    -(void)test
    {
        //分别给两个成员变量赋初始值
        hasBlock = @"ludashi";
        noBlock = @"ludashi";
        NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
        NSLog(@" noBlock = %@,  noBlock_p = %p", noBlock, noBlock);
         
        //定义block
        void (^myBlock)() = ^()
        {
            //修改加__block的成员变量的值
            hasBlock = @"ludashi_update";
            NSLog(@"block中输出的内容");
            NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
            NSLog(@" noBlock = %@,  noBlock_p = %p", noBlock, noBlock);
        };
         
        //改变noBlock的值
        noBlock = @"ludashi_update";
        NSLog(@"更新后的值");
        NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
        NSLog(@" noBlock = %@,  noBlock_p = %p", noBlock, noBlock);
      
        //调用block
        myBlock();
         
        //调用block后的值
        NSLog(@"调用myBlock后的值");
        NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
        NSLog(@" noBlock = %@,  noBlock_p = %p", noBlock, noBlock);
    }
    @end

        ​输出结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    2014-08-10 16:32:42.497 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x100006188
    2014-08-10 16:32:42.499 Memory[1349:303]  noBlock = ludashi,  noBlock_p = 0x100006188
    2014-08-10 16:32:42.499 Memory[1349:303] 更新后的值
    2014-08-10 16:32:42.500 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x100006188
    2014-08-10 16:32:42.500 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828
    2014-08-10 16:32:42.500 Memory[1349:303] block中输出的内容
    2014-08-10 16:32:42.501 Memory[1349:303] hasBlock = ludashi_update, hasBlock_p = 0x100006828
    2014-08-10 16:32:42.501 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828
    2014-08-10 16:32:42.501 Memory[1349:303] 调用myBlock后的值
    2014-08-10 16:32:42.502 Memory[1349:303] hasBlock = ludashi_update, hasBlock_p = 0x100006828
    2014-08-10 16:32:42.502 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828

    总结:

    1. 对于一个、多个成员变量,不管是否用__block修饰(用不用都没任何影响),block结构体会生成一个成员 :self,并且会引用成员变量所属的对象实例 self。

    2. 对于成员变量的修改都是通过对象self指针引用来实现的。

    3. block内部对于成员变量的访问也是通过block结构体对象的成员self 指针引用来实现的。

  • 相关阅读:
    [Swift实际操作]七、常见概念-(2)点CGPoint和变形CGAffineTransform的使用
    [Swift实际操作]七、常见概念-(1).范围Range、ClosedRange和NSRange的使用实际操作
    [Swift]LeetCode263. 丑数 | Ugly Number
    [Swift]LeetCode258. 各位相加 | Add Digits
    [Swift]LeetCode920. 播放列表的数量 | Number of Music Playlists
    Web开发中,使用表格来展示每个角色对应的权限
    Web开发中,使用表格来展示每个角色对应的权限
    请妥善保管自己的QQ等网络帐号
    请妥善保管自己的QQ等网络帐号
    网络广告行业资料整理
  • 原文地址:https://www.cnblogs.com/SnowStark/p/5607417.html
Copyright © 2011-2022 走看看