深入学习block
首先,什么是block?block其实就是一个代码块,把你想要执行的代码封装在这个代码块里,等到需要的时候再去调用。那block是OC对象吗?答案是肯定的。
做一道很简单的关于block的测试题:
int (^testBlock) (int) = ^(int num) { return num++; }; NSLog(@"%d", testBlock(testBlock(testBlock(3)) ));
这道题是我公司面试题中的一道,来面试的都是至少两年工作经验的,但是很郁闷,这道题绝大多数人写的都是6。。正确结果为:3。
以下讲解的内容均是ARC环境下。
一、block的分类
-
NSStackBlock:栈block
-
NSMallocBlock:堆block
-
NSGlobalBlock:全局block
1.NSStackBlock:
特点:生命周期由系统控制,函数返回即销毁
用到局部变量、成员属性\变量,且没有强指针引用的block都是栈block
int (^testBlock) (int) = ^(int num) { return num++; }; NSLog(@"%d", testBlock(testBlock(testBlock(3)) ));
注意:不是没有强指针(copy或strong)引用的block,就是栈block,也有可能是全局block(下面会介绍什么是全局block)。
2.NSMallocBlock:
特点:没有强指针引用即销毁,生命周期由程序员手动管理
栈block如果有强指针引用或copy修饰的成员属性引用就会被拷贝到堆中,变成堆block
//堆block int j = 0; void(^mallocBlock)() = ^ { NSLog(@"%d",j); }; NSLog(@"%@",mallocBlock); //输出结果 <__NSMallocBlock__: 0x7f8cd351db80>
上面代码也没用看到strong 或 copy修饰符,但是为什么会强引用的,因为在ARC环境下,我们在声明变量的时候,前面是会被默认加上 __strong 修饰符的。所以我们在ARC下声明的Block一般都是堆block。
3.NSGlobalBlock:
特点:命长,有多长?很长很长,人在塔在(应用程序在它就在)
没有用到外界变量,或者只用到全局变量、静态(static)变量的block就是全局block
对于全局block,用weak,strong,还是copy修饰都是可以的。(但最好不用用weak)
//全局block void (^globalBlock) () = ^ { NSLog(@"%d",staticNum); }; NSLog(@"%@",globalBlock); //输出结果 <__NSGlobalBlock__: 0x108152110>
注意:如果block中没有用到外界变量,不管他是用什么修饰符修饰,他都是全局block!
例如:
void (^global2Block) () = ^ { NSLog(@"globalBlock"); }; NSLog(@"%@",global2Block); // 输出结果 <__NSGlobalBlock__: 0x1023a0150>
二、block对外界变量的捕获
1.1 基本数据类型:局部变量
block会拷贝该变量的值当做常量使用,外界修改变量的值不会影响block内部,且block内部不能对其修改
block内部修改外界变量i的值直接报错,如果想要修改,可以在int a = 0前面加上关键字__block,此时i等效于全局变量或静态变量
int a = 0; void (^block1)() = ^ { NSLog(@"a = %d",a); }; a++; block1(); //输出结果 a = 0; __block int b = 0; void (^block2) () = ^ { NSLog(@"b = %d",b); // 输出结果 b = 0; b = 2; }; block2(); NSLog(@"b = %d",b); //输出结果 b = 2;
1.2 基本数据类型:成员变量(实例变量),静态变量,全局变量
block直接访问变量地址,在block内部可以修改变量的值,并且外部变量被修改后,block内部也会跟着变
self.num = 1; self.num ++; void (^block3) () = ^ { self.num++; }; block3(); NSLog(@"%d",self.num); //输出结果为 3
2.1 指针类型: 局部变量
block会复制一份指针并强引用指针所指对象,且内部不能修改指针的指向,但是可以修改指针所指向对象的值
NSMutableString *str = @"abc".mutableCopy; void (^block4) () = ^ { // str = @"def"; 报错 [str appendString:@"def"]; NSLog(@"str = %@",str); }; str = @"123".mutableCopy; block4(); //输出结果为 "adbdef"
2.2 指针类型: 成员变量(实例变量),静态变量,全局变量
block不会复制指针,但是会强引用该对象,内部可修改指针指向,block会强引用成员属性\变量所属的对象,这也是为什么block内部用到self.xxx或_xxx可能会引起循环引用的原因
static NSString *staticStr = @"abc"; void (^block5) () = ^ { NSLog(@"staticStr = %@",staticStr); staticStr = @"def"; NSLog(@"staticStr = %@",staticStr); }; staticStr = @"123"; block5(); //输出结果为 staticStr = 123 staticStr = def
相关文章
- Milvus深入理论学习和实战学习
- HCIE-Security Day32:IPSec:深入学习ipsec ikev1、主模式、野蛮模式、快速模式、dh算法、预共享密钥
- (《机器学习》完整版系列)第14章 概率图模型——14.11 趣谈话题模型(隐狄利克雷分配模型LDA)
- 周末学习记录——2019-3-24
- 自动化测试 python2.7 与 selenium 2 学习
- opencv3中的机器学习算法之:EM算法
- 27岁才开始学习编程靠谱吗?45岁都不晚
- SQL JOIN 入门使用示例学习左连接、内连接、自连接
- storm学习
- 面向分布式强化学习的经验回放框架——Reverb: A Framework for Experience Replay
- Python学习---面向对象的学习[深入]
- Hadoop学习---Hadoop的深入学习
- IOS深入学习(20)之Object modeling
- 条件概率与条件独立学习笔记
- Java学习路线:day14 面向对象(下)
- LWIP学习系列(二):STM32中ETH外设的配置与LWIP的结合使用