底层探索--Block的本质

2021-10-12  本文已影响0人  永断阎罗

底层分析

闭包如何使用局部变量、静态局部变量和全局变量?

变量类型 捕获到Block内部 访问方式
局部变量 值传递(浅拷贝)
静态局部变量 指针传递
全局变量 直接访问

说明:对于局部变量(自动变量auto),闭包里保存瞬时值,在闭包范围后改变局部变量的值不会影响Block内部值得变化。
注意:

  1. 对于对象变量,(比如:NSString *name = @"",直接传name是传递指向的堆内存指针值,而&name则是自身所在内存的指针)

  2. 特别说明:静态局部变量,Block捕获时就用的是&变量,然后内部申明相应变量指针将其存起,从而内部可以修改其值。

    对于局部变量(自动变量auto):闭包里保存瞬时值,并且是值传递
    a.基础变量:直接捕获其值(内存值),在闭包之后改变,闭包内部不会有任何变化;
    b.不可变对象变量:捕获其值(内存值),在闭包之后改变(重新赋值,相当于改变了其指针指向,但闭包内部捕获时强引用故对象还存在,闭包内部不会有任何变化);
    c.可变对象变量:捕获其值(内存值),在闭包之后改变(重新赋值,相当于改变了其指针指向,但闭包内部捕获时强引用故对象还存在,闭包内部不会有任何变化,但自身增删改,而指针未变,指向的值块也跟着变,则闭包内部的值块也会跟着改变);
    静态局部变量:捕获其指针值,在闭包之后改变(闭包内部会跟着变,因为静态变量,自初始话~销毁,指针都不会改变)(注:初始化一个全局变量或static变量时,只能用常量赋值,不能用变量赋值)
    全局变量:不会捕获到内部,而是直接访问。故在闭包之后改变,闭包内部也会跟这变化

特殊:对于方法内部的 self,也是自动变量
因为:OC方法转换为C语言函数时,会默认转换为如下格式:
返回值 方法名(类 *self, SEL _cmd) {}
故:self 和 _cmd 也是auto变量

ARC下,Block的类型和使用变量的关系图?

Block类型 环境 存储环境 copy效果
__NSGlobalBlock__ 没有访问任何auto变量 数据区域 什么也不做
__NSMallocBlock__(MRC下为__NSStackBlock__) 访问了auto变量 堆(MRC下为堆) 引用计数+1(从栈复制到堆)
__NSMallocBlock__ 上面Malloc/Stack调用了copy 引用计数+1

__block可以用于解决block内部无法修改auto变量值的问题
__block不能修饰全局变量、静态变量(static)
编译器会将__block变量包装成一个对象
调用的是,从__Block_byref_age_0的指针找到age所在的内存,然后修改值

总结一下在Block中改变变量值有2种方式,一是传递内存地址指针到Block中(比如用:static 静态局部变量),二是改变存储区方式(__block)。

ARC下,哪些情况会自动进行Copy操作?

循环引用

Block知识总结

面试题

1、 block的原理是怎样的?本质是什么?

本质:Block俗称闭包,是一个匿名函数,本质是封装了函数调用以及调用环境的OC对象。
原理:block内部或捕获其内部使用到的auto变量和静态变量,使其延时调用时依然能使用其外部变量。

2、 __block的作用是什么?有什么使用注意点?

作用:使其block内部能修改外部的auto变量。
注意点:不要滥用,不能用于修饰静态变量。

3、 block的属性修饰词为什么是copy?使用block有哪些使用注意?

在ARC环境下,不一定费用copy,可用copy和strong,效果一样都会拷贝到堆上。
使用注意:避免循环引用问题,和使用弱引用的对象时提前释放内存问题。

4、 block在修改可变的对象时,需不需要添加__block?

不需要,因为是值传递,Block内部会自动生成对象来引用外部可变变量,所以此对象的增删改是可以的,但不能改变其指针指向(因为相当于在另一个函数内部修改另一个函数内部的局部变量的指针指向,是不能的)。

上一篇 下一篇

猜你喜欢

热点阅读