zoukankan      html  css  js  c++  java
  • block 解析

    局部变量

    block内使用局部变量,一般都是截获变量(只读),截获离block初始化最近的一次的值。
    引用官方文档:
    1. Stack (non-static) variables local to the enclosing lexical scope are captured as const variables.Their values are taken at the point of the block expression within the program. In nested blocks, the value is captured from the nearest enclosing scope. 
     
    我们做一个测试,了解一下原理
    代码如下:
    -(void )test3
    {
        NSString *_person2=@"person2";
        NSMutableArray *_listTest=[[NSMutableArray alloc]init];
        //初始值
        NSLog(@"init _person2:%@,%p",_person2,_person2);
        NSLog(@"init _listTest:%@,%p",_listTest,_listTest);
        void (^myBlock)(int) = ^(int num) {
            //block内赋值
            //        _weakPerson2=@"person22";
            NSLog(@"excuteing _person2:%@,%p",_person2,_person2);
            NSLog(@"excuteing _listTest:%@,%p",_listTest,_listTest);
        };
        //修改前赋值
        _person2=@"person22";
        [_listTest addObject:@"1212"];
        NSLog(@"excutebefore _person2:%@,%p",_person2,_person2);
        NSLog(@"excutebefore _listTest:%@,%p",_listTest,_listTest);
        myBlock(1);
        //block执行后
        NSLog(@"excuteafter _person2:%@,%p",_person2,_person2);
        NSLog(@"excuteafter _listTest:%@,%p",_listTest,_listTest);
    }

     输出一下结果:

    2014-07-29 11:05:29.460 Test[2540:60b] init _person2:person2,0xb18ec
    2014-07-29 11:05:29.463 Test[2540:60b] init _listTest:(
    ),0x17d98560
    2014-07-29 11:05:29.464 Test[2540:60b] excutebefore _person2:person22,0xb193c
    2014-07-29 11:05:29.465 Test[2540:60b] excutebefore _listTest:(
        1212
    ),0x17d98560
    2014-07-29 11:05:29.467 Test[2540:60b] excuteing _person2:person2,0xb18ec
    2014-07-29 11:05:29.468 Test[2540:60b] excuteing _listTest:(
        1212
    ),0x17d98560
    2014-07-29 11:05:29.470 Test[2540:60b] excuteafter _person2:person22,0xb193c
    2014-07-29 11:05:29.471 Test[2540:60b] excuteafter _listTest:(
        1212
    ),0x17d98560
     从日志可以看出:block内部对于可变、不可变的变量都无法修改,而且
    1. 在block初始化后对于NSString 变量  _person2 的修改,并没有同步到block内部,因为这时block外部的变量_person2指针重新指向另外一块内存
    2. 在block初始化后对于NSMutableArray变量 _listTest 的修改,同步到block内部,因为这时block外部的变量 _listTest 指针指向的内存地址没有变,只是对这块内存的值进行了操作。
    我们可以借助  clang -rewrite-objc 转换.c文件得到.cpp文件,也可以转换.m也可以得到cpp文件(可能会有些报错)
    以下是部分转换后的代码
    //这里就是block对象的结构
    //imp:函数指针对象,FuncPtr指向具体block实现的函数
    //_person2:截获的变量
    //isa、flags、funcptr、desc后面会说道。
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    struct __KDBlockTest__test3_block_impl_0 {
      struct __block_impl impl;
      struct __KDBlockTest__test3_block_desc_0* Desc;
      NSString *_person2;
      NSMutableArray *_listTest;
      __KDBlockTest__test3_block_impl_0(void *fp, struct __KDBlockTest__test3_block_desc_0 *desc, NSString *__person2, NSMutableArray *__listTest, int flags=0) : _person2(__person2), _listTest(__listTest) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };

    //block实现的函数
    static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself, int num) {
      NSString *_person2 = __cself->_person2; // bound by copy
      NSMutableArray *_listTest = __cself->_listTest; // bound by copy
    
    
    
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_4,_person2,_person2);
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_5,_listTest,_listTest);
        }
    //block对象的描述信息(大小等等)
    static struct __main1_block_desc_0 {
      size_t reserved;
      size_t Block_size;
    } __main1_block_desc_0_DATA = { 0, sizeof(struct __main1_block_impl_0)};
    //这是objc测试函数test
    static void _I_KDBlockTest_test3(KDBlockTest * self, SEL _cmd) {
        NSString *_person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_1;
        NSMutableArray *_listTest=((id (*)(id, SEL))(void *)objc_msgSend)((id)((id (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("alloc")), sel_registerName("init"));
    
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_2,_person2,_person2);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_3,_listTest,_listTest);
        void (*myBlock)(int) = (void (*)(int))&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _person2, _listTest, 570425344);
    
        _person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_6;
        ((void (*)(id, SEL, id))(void *)objc_msgSend)((id)_listTest, sel_registerName("addObject:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_7);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_8,_person2,_person2);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_9,_listTest,_listTest);
        ((void (*)(__block_impl *, int))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock, 1);
    
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_10,_person2,_person2);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_11,_listTest,_listTest);
    }

    简单分析block截获变量:

     1).block初始化
    void (*myBlock)(int) = (void (*)(int))&__KDBlockTest__test3_block_impl_0((void *)__KDBlockTest__test3_block_func_0, &__KDBlockTest__test3_block_desc_0_DATA, _person2, _listTest, 570425344);
    传入了参数:函数指针、block描述、外部变量 _person2 和 _listTest,这时候在block内部对 _person2、_listTest 进行了引用
    : _person2(__person2), _listTest(__listTest)
    1. 在block初始化后,我们对 _person2 做了修改,重新指向了 0xb193c 这块内存,但是不会影响block结构体成员_person2,因为成员 _person2 指向的是 0xb18ec。
    2. 向 _listTest 数组中添加了一个元素,并没有改变它的内存地址,依然还是 0x17d98560 
    _person2=(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_6;
        ((void (*)(id, SEL, id))(void *)objc_msgSend)((id)_listTest, sel_registerName("addObject:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_7);
    2).执行block
    ((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);

    其实还是调用了block对象里的函数对象(_block_imp1)的函数指针(FuncPtr) 所指向的函数__main1_block_func_0,并把block自己作为参数传递进去。

    static void __KDBlockTest__test3_block_func_0(struct __KDBlockTest__test3_block_impl_0 *__cself, int num) {
      NSString *_person2 = __cself->_person2; // bound by copy
      NSMutableArray *_listTest = __cself->_listTest; // bound by copy
    
    
    
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_4,_person2,_person2);
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_5l_2l25j3tn0wl_3zy1hpsq1rhc0000gp_T_KDBlockTest_6946c5_mi_5,_listTest,_listTest);
        }

     

    总结:对于局部变量,变量不加__block修饰符,在block内部是无法修改变量的值。而且

    1. 对值类型的修改,如果block初始化后,无法同步到block内部
    2. 对于引用类型的修改,如果block初始化后,修改指针指向,即指向另外一块内存,这样也是无法同步到block内部
    3. 对于引用类型的修改,如果block初始化后,对指针指向的内存进行修改,即NSMutableArray add 、remove操作,这样是可以用同步到block内部,但block内部同样无法修改。
  • 相关阅读:
    opengl画不出直线 线段 坐标轴 却能画出其他图形的坑
    c++多个文件中共用一个全局变量 变量跨文件使用
    关于c# winform 键盘响应右边键盘消息响应事件的上下左右方向键没有反应
    关于c#winform用sharpGL(OpenGL)绘制不出图形,绘制窗口是个黑框的坑
    C# winform用sharpGL(OpenGl)解析读取3D模型obj
    关于C#界面开发winform与SharpGL结合鼠标只在OpenGLControl绘图区域显示坐标移动消息响应(c#鼠标单独在某个控件上的消息响应)
    关于MFC与OpenGL结合绘图区域用鼠标来控制图形的移动的坑
    bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑
    OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转
    OpenGl 实现鼠标分别移动多个物体图形 ----------移动一个物体另外一个物体不动--读取多个3d模型操作的前期踏脚石
  • 原文地址:https://www.cnblogs.com/NarutoYq/p/3873109.html
Copyright © 2011-2022 走看看