xcrun -sdk iphonesimulator clang -rewrite-objc ViewController.m
注意:ARC环境下编译器,会自动帮我们添加copy操作。
1、block有三种:
NSStackBlock存储于栈区
NSGlobalBlock存储于程序数据区
NSMallocBlock存储于堆区
NSGlobalBlock 静态区block,这是一种特殊的bloclk,因为不引用外部变量而存在。另外,作为静态区的对象,它的释放是有操作系统控制的,这一点我们最后再聊。
NSStackBlock 栈区block,位于内存的栈区,一般作为函数的参数出现。 需要引入外部参数,arc环境下不能赋值,否则编译器会自动添加copy操作,变成堆block
NSMallocBlock 堆区block,位于内存的堆区,一般作为对象的property出现。
ARC环境下
void (^block)(void) = ^{
NSLog(@"hello block");
};
NSLog(@"block = %@",block); // 全局静态block: __NSGlobalBlock__ 地址段以0x1开头
int a = 10;
void (^block1)(void) = ^{
NSLog(@"hello bloc %d ",a);
};
NSLog(@"block = %@",block1); // __NSMallocBlock__ 堆block 地址段以0x6开头
NSLog(@"%@",^{
NSLog(@"hello bloc %d",a); // __NSStackBlock__ 栈block 地址段以0x7开头
});
log日志:
2019-08-18 23:05:59.207457+0800 block[3171:134706] block = <__NSGlobalBlock__: 0x101b49ac0>
2019-08-18 23:05:59.207626+0800 block[3171:134706] block = <__NSMallocBlock__: 0x6000009c9da0>
2019-08-18 23:05:59.207729+0800 block[3171:134706] <__NSStackBlock__: 0x7ffeee16d318>
int a = 10;
[self uuuuuu:^{
NSLog(@"hello bloc %d ",a);
}];
- (void)uuuuuu:(void(^)(void))clock{
NSLog(@"%@",clock);
int a = 10;
NSLog(@"%@",^{
NSLog(@"hello bloc %d",a); // __NSStackBlock__ 栈block 地址段以0x7开头
});
}
log: 2019-08-18 23:19:27.630741+0800 block[3335:145771] <__NSStackBlock__: 0x7ffee0e9d388>
2019-08-18 23:19:27.630809+0800 block[3335:145771] <__NSStackBlock__: 0x7ffee0e9d330>
屏幕快照 2019-08-18 下午11.34.27.png
__block 修饰符
屏幕快照 2019-08-18 下午11.35.59.png
这里是使用
操作不需要添加__block修饰符
屏幕快照 2019-08-18 下午11.38.12.png
这里是赋值
操作不需要添加__block修饰符
屏幕快照 2019-08-20 下午10.44.17.png
屏幕快照 2019-08-20 下午10.48.38.png
在栈上创建的block,注意:block在栈上创建
对栈block的进行copy操作,发生了什么
总结 在栈上对__block变量进行修改,如果此时我们队栈上的__block变量已经做过copy操作之后,实际上我们修改的不是栈上的__block变量的值;而是通过栈上的__block变量内部的__forwording指针,找到堆上面的__blcok变量,然后对堆上的__block变量的值进行修改。
如果对堆上面的__block变量进行修改,是通过自身(堆)上面的__block变量内部的__forwording指针进行修改。
问题 (3)在block内如何修改block外部变量?
注释:我们都知道:Block不允许修改外部变量的值,这里所说的外部变量的值,指的是栈中指针的内存地址。__block 所起到的作用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。
__block 所起到的作用就是只要观察到该变量被 block 所持有,就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值。
2、Block劫持变量特性
- 对于
基本数据
类型的局部变量
截获其值 - 对于
对象
类型的局部变量 连同所有权修饰符
一起截获 - 对于
局部静态变量
以指针的形式
进行截获 - 对于
全局变量、静态全局变量
不截获
如下代码编译之后源码
// 全局变量
int global_a = 30;
// 静态全局变量
static int static_global_a = 40;
- (void)method{
// 局部变量
int a = 10;
// 局部对象
NSObject *obj_a = [NSObject new];
// 局部静态变量
static int static_a = 20;
void (^Block)(void) = ^(void){
NSLog(@"%d",a);
NSLog(@"%@",obj_a);
NSLog(@"%d",static_a);
NSLog(@"%d",global_a);
NSLog(@"%d",static_global_a);
};
Block();
}
// 全局变量
int global_a = 30;
// 静态全局变量
static int static_global_a = 40;
struct __MCBlock__method_block_impl_0 {
struct __block_impl impl;
struct __MCBlock__method_block_desc_0* Desc;
// 截获局部变量的值
int a;
// 连同对象所有权一起截获
NSObject *obj_a;
// 以指针的形式截获静态局部变量
int *static_a;
// 全局变量、静态全局变量不对其截获
__MCBlock__method_block_impl_0(void *fp, struct __MCBlock__method_block_desc_0 *desc, int _a, NSObject *_obj_a, int *_static_a, int flags=0) : a(_a), obj_a(_obj_a), static_a(_static_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
请看如下例子1、:
int a = 10;
void (^block)(void) = ^{
a = 20;
NSLog(@"%d",a);
};
请问此时编译之后的结果:
此时会抛出:Variable is not assignable (missing __block type specifier)
因为block对基本数据类型局部变量是值的传递,这时候我们在block里面去修改外部变量的值,是不允许的。举例:方法中的参数,我们可以在方法内部打印其值,但是我们不能够去修改参数的值
请看如下例子2、:
// 局部变量
int a = 10;
void (^block)(void) = ^{
NSLog(@"%d",a);
};
a = 20;
block();
请问此时打印多少? 打印 10;
请看如下例子3、:
// __block 修饰的局部变量
__block int a = 10;
void (^block)(void) = ^{
NSLog(@"%d",a);
};
a = 20;
block();
a = 30;
请问此时打印多少? 打印 20;
请看如下例子3、:
// 局部静态变量
static int a = 10;
void (^block)(void) = ^{
NSLog(@"%d",a);
};
a = 20;
block();
a = 30;
请问此时打印多少? 打印 20;
请看如下例子4、:
// 局部全局变量
static int a = 10;
{
void (^block)(void) = ^{
NSLog(@"%d",a);
};
a = 20;
block();
a = 30;
}
请问此时打印多少? 打印 20;
请看如下例子5、:
// 静态全局变量
static int a = 10;
{
void (^block)(void) = ^{
NSLog(@"%d",a);
};
a = 20;
block();
a = 30;
}
请问此时打印多少? 打印 20;
请看如下例子6、:
// 全局变量
int a = 10;
{
void (^block)(void) = ^{
NSLog(@"%d",a);
};
a = 20;
block();
a = 30;
}
请问此时打印多少? 打印 20;
请看如下例子7、:
@interface ViewController ()
@property (nonatomic, assign) NSInteger a;
end
@implementation ViewController
- (void)viewDidLoad {
void (^block)(void) = ^{
NSLog(@"%ld",(long)_a);
};
_a = 20;
block();
_a = 30;
}
@end
请问此时打印多少? 打印 20;
网友评论