iOS多线程编程和内存管理-----修改Block语法中的值(3)

因为Block语法可以截获自动变量的值,因为在实现上不能修改被截获自动变量的值(因为在block初始化时,自动变量的值保存在block的结构体实例中),所以修改被截获自动变量的值会报编译错误
如果我们要修改Block中的值,或者说在Block中保存值;有两种解决方法
(1)C语言中的静态变量、静态全局变量、全局变量,允许Block修改值
(2)使用__block修饰符,带有__block的变量,允许Block修改值

下面来具体解释原因
(1)C语言中的静态变量、静态全局变量、全局变量,允许Block修改值


int global_val = 1;
static int  stativ_global_val = 2;

int main(int argc, const char * argv[]) {

    static int static_val = 3;

    void (^blk)(void) = ^{
        global_val *= 1;
        stativ_global_val *= 2;
        static_val *=3;

    };

    return 0;
}

分析源码


int global_val = 1;
static int stativ_global_val = 2;


struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int *static_val;//局部的静态变量出现在__main_block_impl_0结构体中

//构造函数中传入static_val的信息
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int *static_val = __cself->static_val; // bound by copy

      //静态全局变量和全局变量的访问变换前后没变化
        global_val *= 1;
        stativ_global_val *= 2;
        (*static_val) *=3;
        printf("%d,%d,%d",global_val,stativ_global_val,(*static_val));
    }

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {

    static int static_val = 3;

    void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &static_val));

    ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
    return 0;
}

分析:

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
       int *static_val = __cself->static_val; // bound by copy

      //静态全局变量和全局变量的访问变换前后没变化
        global_val *= 1;
        stativ_global_val *= 2;

        (*static_val) *=3;
        printf("%d,%d,%d",global_val,stativ_global_val,(*static_val));
    }

由源码看出对静态变量的访问转变为(*static_val) *=3; 使用static_val指针访问静态变量,将静态变量static_val的指针放在__main_block_impl_0结构体的构造函数保存。这是超出作用域使用变量的简单方法。

(2)使用__block修饰符,带有__block的变量,允许Block修改值

int main(int argc, const char * argv[]) {

    __block int val = 10;
    void (^blk)(void) = ^{ val = 1;};

    return 0;
}
struct __Block_byref_val_0 {
  void *__isa;
__Block_byref_val_0 *__forwarding;
 int __flags;
 int __size;
 int val;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  // __main_block_impl_0持有指向__Block_byref_val_0实例的指针
  __Block_byref_val_0 *val; 

  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val, int flags=0) : val(_val->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }

};


static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_val_0 *val = __cself->val; // bound by ref
 (val->__forwarding->val) = 1;
}

static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->val, (void*)src->val, 8/*BLOCK_FIELD_IS_BYREF*/);

}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {
_Block_object_dispose((void*)src->val, 8/*BLOCK_FIELD_IS_BYREF*/);
}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 
0, 
sizeof(struct __main_block_impl_0), 
__main_block_copy_0,
 __main_block_dispose_0
 };


int main(int argc, const char * argv[]) {

    __attribute__((__blocks__(byref))) __Block_byref_val_0 val = 
    {   (void*)0,
        (__Block_byref_val_0 *)&val,
         0, 
         sizeof(__Block_byref_val_0),
        10
    };

    void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_val_0 *)&val, 570425344));


    return 0;
}

分析:

(1)在自动变量前加__block修饰符,__block int val = 10; 会在源代码中转变为如下结构体实例

   __attribute__((__blocks__(byref))) __Block_byref_val_0 val = 
    {   (void*)0,
        (__Block_byref_val_0 *)&val,
         0, 
         sizeof(__Block_byref_val_0),
        10
    };

即__block变量变成了__Block_byref_val_0结构体类型的自动变量,即栈上生成__Block_byref_val_0结构体实例。

struct __Block_byref_val_0 {
  void *__isa;
__Block_byref_val_0 *__forwarding;//持有指向结构体实例的指针
 int __flags;
 int __size;
 int val;//val也出现在结构体中作为成员变量
};

(2)^{ val = 1;}; 转换成下面代码

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_val_0 *val = __cself->val; // bound by ref
 (val->__forwarding->val) = 1;

 }

cself是指向__main_block_impl_0 结构体的指针,__main_block_impl_0结构体中增加了一项,即__Block_byref_val_0 *val;也就是__main_block_impl_0结构体的实例持有指向__Block_byref_val_0结构体实例的指针。

__Block_byref_val_0结构体实例的成员变量__forwarding持有指向该实例自身的指针。通过__forwarding访问变量val。·

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的修养

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值