ios学习笔记——Block块小结
一、块的基础知识
块与函数类似。尤其跟函数指针非常相思,用法也大同小异。
块的语法结构如下:
return_type (^block_name)(parameters)
返回类型 块名称 参数
1 //定义块 2 int (^sjzBlock)(int a, int b) = ^(int a, int b){ 3 return a + b; 4 }; 5 //使用块 6 int c = sjzBlock(1, 2);
在声明块的范围内,所有变量都可以为其所捕获。但是不能修改变量,如果想要修改,可以在声明变量的时候加上__block修饰符。
1 //在块里修改e的值,报错 2 int e = 100; 3 //加上__block修饰符,可以修改d的值 4 __block int d = 10; 5 int (^sjzBlock)(int a, int b) = ^(int a, int b){ 6 d = 12; 7 // e = 90; //报错 8 return a + b; 9 }; 10 int c = sjzBlock(1, 2); 11 NSLog(@"c = %d d = %d", c, d);
输出结果:
块本身也是一个对象,也有引用计数。
如果块所捕获的变量是对象类型,那么就会自动保留它。系统在释放这个块的时候,也会将其一并释放。
块可以访问类的所有实例变量,块能够修改实例变量,所以在声明实例变量时,无需加__block。如果通过读取或写入操作捕获实例变量,那么也会自动把self变量一并捕获了,因为实例变量是与self所只带的实例关联在一起的。当块保留self的时候,很可能self也保留了块,容易造成循环引用。
1 #import "ViewController.h" 2 3 @interface ViewController () 4 5 @property (nonatomic, strong) NSString * sjzStr; 6 7 @end 8 9 @implementation ViewController 10 11 - (void)viewDidLoad { 12 [super viewDidLoad]; 13 14 [self blockText]; 15 } 16 17 - (void)blockText 18 { 19 void (^sjzBlock)(int a, int b) = ^(int a, int b){ 20 //以下这两种调用,都会将会捕获self 21 // _sjzStr = @"Hello, world"; 22 self.sjzStr = @"hello, world"; 23 NSLog(@"%@", _sjzStr); 24 }; 25 26 sjzBlock(1, 2); 27 } 28 29 @end
块的内部结构
这里面,最重要的是invoke变量,是一个函数指针,指向块的实现代码。至少接受一个void*类型的参数,此参数代表块本身。
descriptor变量是指向结构体的指针,每个块都包含改结构体。声明了块的总体大小,copy函数指针保留捕获的对象,dispose当块释放时,释放捕获的对象。
块会把它捕获的对象全部拷贝一份,捕获了多少对象,就要占据多少内存空间。