OC 的 Block 简析1 - 三种类型
本文主要介绍 Block 的三种类型。
一、Block 是什么?
在 OC 文档的 Working with Blocks 中:
Blocks are Objective-C objects, which means they can be added to collections like NSArray
or NSDictionary
.
Block 官方文档: Block Programming Topics 中:
As an optimization, block storage starts out on the stack—just like blocks themselves do.
block 是一个 OC 对象,但是它和普通的O从对象又不一样。
block 默认在 栈上分内存,而我们一般的对象是在堆上。
二、block 有三种类型: 全局 / 栈 / 堆 block
1、全局block - __NSGlobalBlock__
- (void)block3 { // 声明: typedef NSString *(^MyBlock)(NSString *str); MyBlock block = ^(NSString *str){ NSLog(@"处理一些无关于外部属性的事务"); return str; }; block(@""); NSLog(@"block类型%@",block); }
2、栈block - __NSStackBlock__
- (void)block2 { int a = 1; NSLog(@"block类型%@",^{ NSLog(@"block 0:%i", a); }); }
3、堆block - __NSMallocBlock__
- (void)block1 { void (^blockObject)(void); blockObject = ^{ NSLog(@"block 0:%i", a); }; blockObject(); NSLog(@"block类型%@",blockObject); }
从上面3部分代码中,我们可看出三者区别:
全局block:block 没有访问任何外部变量的;
栈block: block 访问了外部对象,但没有copy操作;
堆block:相对于栈block来说:我们声明定义了一个block同时访问了外部变量则(不访问就是全局)(不声明定义就是栈),此过程本质就是栈-变->堆的过程,系统帮我们做了copy,栈的block迁移到了堆里。
4、关于堆block 详解
代码示例:
- (void)block1 { /* __block 允许block内部使用, */ __block NSString *blockStr = @"局部str"; MyBlock block = ^(NSString *str){ /* block 内部操作:将对象 copy 了一个新的到堆上,指针不变,但指针指向新的对象 */ self->globalStr = @"block内修改全局"; blockStr = str; NSLog(@"内globalStr== %@ %p %p",self->globalStr,self->globalStr,&self->globalStr); [self logstr:blockStr]; return str; }; NSLog(@"block类型%@",block); NSLog(@"外globalStr== %@ %p %p",globalStr,globalStr,&globalStr); NSLog(@"外blockStr== %@ %p %p",blockStr,blockStr,&blockStr); block(@"执行block,改局部str"); } - (void)logstr:(NSString *)blockStr { NSLog(@"globalStr2== %@ %p %p",globalStr,globalStr,&globalStr); /* 局部str,拿到外部,创建了一个新的指向它的指针 */ NSLog(@"blockStr2== %@ %p %p",blockStr,blockStr,&blockStr); }
运行结果如图:
我们可以看到,不论是函数中的局部变量 还是当前文件范围的局部变量(注意:代码里的‘全局’并非是真正的全局,只是为了用来区分函数内部变量), 在 block 内部进行使用,对象都不是外部的那个对象了,但是指向对象的指针不变 --> 即:指针指向的对象是一个copy出来的新的。如下图:
从而,也可知,block内部会对我们的对象进行copy,但是指向对象的指针不变,指针指向对象会变成新的。
而函数内部的局部变量被拿出去函数外部使用时,相当于 创建了一个新 的指向这个改变后对象的 指针。
待续... ...
以上。