block如何分类?其实blcok的分类主要是根据block的内存管理来说的,系统把Block分为3类:NSGlobalBlock,NSStackBlock, NSMallocBlock
NSGlobalBlock :位于内存全局区
NSMallocBlock :位于内存堆区
NSStackBlock :位于内存栈区
内存五大区
栈区,堆区,静态区(全局区),常量区,代码区
动态数据区一般就是”堆栈”,栈是线性结构,堆是链式结构. 本地变量在堆栈中.通过堆栈的基地址和偏移量来访问本地变量
动态内存分配有系统根据程序需要即时分配,且分配的大小就是程序要求的大小.
全局变量(一般用static修饰的变量)和静态变量分配在静态区(需要预先分配存储空间)
静态内存分配:分配固定大小的内存分配方法,大多情况下会浪费大量的内存空间,少数情况下,当定义的数组不够大时,会引起越界.
block的结构体如下
Block是带有自动变量的匿名函数;
有三种类型的Block:
_NSConcreteGlobalBlock
_NSConcreteStackBlock
_NSConcreteMallocBlock
Block截获外面的自动变量:
全局变量不会被截获;
没有被__block修饰的int,block体中对这个变量的引用是值拷贝,在block中是不能被修改的;
通过__block修饰的int,block体中对这个变量的引用是指针拷贝,它会生成一个结构体,复制这个变量的指针引用,从而达到可以修改变量的作用;
Block发生copy时机:
block作为方法或函数的返回值时,编译器会自动完成copy操作。
当block赋值给通过strong或copy修饰的id或block类型的成员变量时。
当 block 作为参数被传入方法名带有 usingBlock 的 Cocoa Framework 方法或 GCD 的 API 时。
带有自动变量(局部变量)的 匿名函数 。这个定义满足以下三点:
1.block是一个函数
2.block是一个没有名字的函数
3.block有参数列表,但是这个参数列表是局部变量
block经常使用省略语法,那么意味着省略了一些不必要的东西,我们一步步解析。
1.block完整语法:
^ 返回值类型 参数列表 表达式
^int (int count){ return count + 1}
2.省略返回值类型后:
^ 参数列表 表达式
^ (int count){ return count + 1}
3.省略参数与返回值后:
^ 表达式
^{ printf("Blocks")}
可以看到,对比正常函数语法:
- 返回值类型 函数名 参数列表 表达式
- int name(int count) { return count + 1}
完整语法block实际上与普通函数的区别在于, 没有函数名,并使用 ^ 来表明是block函数。
block也可以作为变量使用,正常定义变量时,需要给出变量类型以及变量名,使用block也是如此。
声明block类型的变量格式如下:
返回值 ^变量名 参数
int (^blk) (int )
我们看到,block变量和正常变量区别在于,多了返回值,以及参数。那我们又该如何赋值呢?
block变量赋值方式:
变量 = 具体block语法
int (^blk) (int ) = ^int (int count){ return count + 1}
这很好理解,block变量也是block类型,赋值时一定也是等于具体的block。
这里,我们来讲一些block作为变量使用的方式,
1.通过Typedef 在函数参数和返回值中使用Block变量:
首先要定义 typedef int(^blk_t)(int)
block作为函数参数 void func(blk_t blk){ }
block作为函数返回值 blk_t func(){ }
2.
typedef int(^blk_t)(int)
blk_t blk = ^(int count){return count + 1}
int result = blk(10)
1.“带有自动变量值”在Blocks中表现为“截获自动变量值”,在Block被赋值时获取当时的变量值并在以后使用。
int value = 2
void (^block)(void) = ^{
NSLog(@"%i",value)
}
value = 10
block()//输出 2
2.未添加__block的情况下:截获OC对象, 调用变更对象的方法不会有问题 ,因为block内会截获该对象的结构体实例指针.但是 不能对该对象进行赋值 操作
id array = [[NSMutableArray alloc] init]
void (^blk) (void) = ^{
id obj = [[NSObject alloc] init]
[array addObject:obj]//这是可行的
array = [[NSMutableArray alloc] init]//这是不可行的
}
若想在Block的表达式中将值赋给外部声明的自动变量,需要在该自动变量上附加__block
__block int value = 2
void (^block)(void) = ^{ value = 10}
block()
NSLog(@"%i",value)//输出10