网上关于block的解释已经很多了,在此,本文仅对block的精简解读。
一、block是什么?
block在OC中是对象,在运行时会被转化成函数。但是block与OC中其他对象最大的不同是:一般来说,block初始化是储存在栈区的。关于block在内存中的储存位置我们在下面的内容中探讨。因为情况是在是太多了。
block的定义:
struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *); }; struct Block_layout { void *isa; //isa指针,这是OC对象的证明 int flags; int reserved; void (*invoke)(void *, ...); //这个invoke指针指向block被转化成的函数 struct Block_descriptor *descriptor; /* Imported variables. */ //如果引用了外部变量,从这里开始列在后面 };
二、block内存地址研究
在开始研究之前,需要说明的是,block中可以访问并且修改全局变量和static变量(无论全局还是局部的)。如果访问非static局部变量,block会被转换成函数,那么就是值传递,并且不能在block中修改传进来的值,编译器会报错的。如果一定要修改非static局部变量的值,请加__block,这样的话,就是传递变量的指针,当然可以修改。
下面简单研究下block的内存地址。
int a=1; static int b=2; - (void)viewDidLoad { [super viewDidLoad]; int c=3; static int d=4; void(^myBlock)()=^{ NSLog(@"myBlock"); }; NSLog(@"myBlock %p",myBlock);//没有访问任何外部变量,block储存在全局区(常量区) NSArray * blockArr=[NSArray arrayWithObjects:^{a=a+c;}, //访问全局变量和局部变量,block储存在堆区 ^{int ss= b +1;}, //访问了全局静态变量,block储存在全局区(常量区)
^{int dd=c+1;}, //访问了局部变量,block储存在栈区
^{d=5+c;},nil]; //访问了局部静态变量和局部变量,block储存在栈区 NSLog(@"%@",blockArr);
打印结果如下:
2015-11-03 21:21:40.936 NSRunloopTest[3668:302834] myBlock 0x10c350310
2015-11-03 21:21:40.937 NSRunloopTest[3668:302834] (
"<__NSMallocBlock__: 0x7feef1732480>",
"<__NSGlobalBlock__: 0x10c350370>",
"<__NSStackBlock__: 0x7fff538b3a08>",
"<__NSStackBlock__: 0x7fff538b39e0>"
)
解释: 为了打印出三种不同类型的block,就随便组合了几种外部变量访问的方式,先说类型,
__NSMallocBlock__:内存地址在堆区的block类型
__NSGlobalBlock__:内存地址在全局区的block类型
__NSStackBlock__: 内存地址在栈区的block类型
比较对应的内存地址,也确实如此,当然,英文名称也说明了一切。block是否访问外部变量,外部变量的类型不同,同时访问多种变量,ARC和MRC,种种条件组合起来,情况是不一样的,下面是一些常见组合的结论:
原文:http://www.cnblogs.com/panyuluoye/p/4934555.html