✅作者简介:大家好我是瓜子三百克,一个非科班出身的技术程序员,还是喜欢在学习和开发中记录笔记的博主小白! 个人主页:瓜子三百克的主页 系列专栏:OC语法 如果觉得博主的文章还不错的话,请点赞+收藏⭐️+留言支持一下博主哦爛

让我们一起卷起来吧!!!

文章目录

1、block修改变量1.1、直接修改变量?1.2、把auto变量改成static变量1.3、把auto变量改成全局变量1.4、auto变量添加 __block 修饰符

2、添加 __block 修饰符之后的底层结构3、修改变量指针与使用变量指针的异同

1、block修改变量

1、__block可以用于解决block内部无法修改auto变量值的问题 2、__block不能修饰全局变量、静态变量(static) 3、编译器会将__block变量包装成一个对象

1.1、直接修改变量?

代码示例:

#import

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

@autoreleasepool {

int age = 10;

void(^block)(void) = ^{

// age = 20;

NSLog(@"Hello1:%d",age);

};

block();

}

return 0;

}

结果: 如果我们直接在block函数修改age变量的值,发现系统会直接报错,无法编译。

1.2、把auto变量改成static变量

这样block内部成员捕获的外部age成员的地址。这样在block内部修改值和赋值也是通过age地址处理的。

1.3、把auto变量改成全局变量

因为全局变量所有的函数都可以访问,block也不会去捕获全局变量到结构体中,直接在函数中取值赋值即可。

1.4、auto变量添加 __block 修饰符

很多时候我们并不想将auto变量改成static变量或全局变量,因为把变量改成全局变量或者static变量,这个变量是一直存在内存中的,不会被释放。这并不是我们想要的,所以我们还是希望他是临时变量,在不需要的时候可以自动销毁。那要怎么处理呢?这里就涉及到一个新的对象修饰符:__block。

见下图,添加 __block 修饰符是可以实现auto变量修改的: __block优势:

1、被修饰的变量可以在block函数中修改和访问。 2、被修饰的变量其性质没有被改变,还是自动变量。

那么加了 __block 修饰符之后,底层做了什么,让block函数内部可以正常修改auto变量?

2、添加 __block 修饰符之后的底层结构

// 程序入口

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

/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;

// 1、用__block 修饰符,cpp底层直接将该auto变量转换成一个结构体对象

__Block_byref_age_0 age = {

0,// isa

&age,//自己的地址

0,// flags

sizeof(__Block_byref_age_0),//当前结构体的大小

10//外部传进来的变量值

};

// 2、定义block变量

void(*block)(void) =

&__main_block_impl_0(// 2.1、block结构体

__main_block_func_0,// 2.2、block函数

&__main_block_desc_0_DATA,

&age,//新定义的结构体变量

570425344

);

block->FuncPtr(block);

}

return 0;

}

// 1、auto变量age的结构体

struct __Block_byref_age_0 {

void *__isa;

__Block_byref_age_0 *__forwarding;//指向自己的指针

int __flags;

int __size;

int age;// age结构体内部才拥有age变量

};

//2.1、block结构体

struct __main_block_impl_0 {

struct __block_impl impl;

struct __main_block_desc_0* Desc;

__Block_byref_age_0 *age; // 2.1a、此时block没有直接存储age变量,而是由age变量生成的结构体指针

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {

impl.isa = &_NSConcreteStackBlock;

impl.Flags = flags;

impl.FuncPtr = fp;

Desc = desc;

}

};

// 2.2、block函数

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

// 2.2a、获取block中的age结构体对象

__Block_byref_age_0 *age = __cself->age; // bound by ref

//2.2b、赋值:取age的成员变量__forwarding(指向自己的指针),再取其中的age变量赋值

(age->__forwarding->age) = 20;

//2.2c、取值:跟赋值一个逻辑

NSLog((NSString *)&__NSConstantStringImpl__var_folders_vc_pn677_yj1sz8hgf_q5bjvssc0000gn_T_main_829ca2_mi_0,(age->__forwarding->age));

}

底层结构图:

3、修改变量指针与使用变量指针的异同

如下图,是可以正常编译和赋值的: 因为这两句代码不是在修改array变量的指针,而是在使用array指针。

[array addObject:@"123"];

[array addObject:@"321"];

1、使用auto变量的指针,不需要 __block ,只有在修改 auto变量的指针,才需要__block 修饰符修饰 auto变量。 2、能不加__block修饰符就不加,因为使用__block修饰符会生成一个新的对象来引用他。

最后如果觉得我写的文章对您有帮助的话,欢迎点赞✌,收藏✌,加关注✌哦,谢谢谢谢!!

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: