博客新地址:www.narutoyq.cc

代码改变世界

block 解析 - 简介

2014-07-26 21:05  小 叶  阅读(1017)  评论(2编辑  收藏  举报

简介

block 类似标准的c函数,除了一些函数体一些可执行的代码,还可以把变量绑定到自动栈或者托管堆上.....和js里的闭包、c# lambda表达式有些类似,实质是一个函数指针。与函数指针的区别在于其可以捕获(capture)其定义时作用域内的变量。

Block objects are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block can therefore maintain a set of state (data) that it can use to impact behavior when executed.
 
格式  :  (返回值)(^Name)(参数列表)
void(^Test)(void)=^{ printf("%s","hello world!"); };
在Objective-C语言中,一共有3种类型的block(可通过isa指针打印查看):
1._NSConcreteGlobalBlock 全局的静态block,不会访问任何外部变量。
2._NSConcreteStackBlock 保存在栈中的block,当函数返回时会被销毁。
3._NSConcreteMallocBlock 保存在堆中的block,当引用计数为0时会被销毁。
需要注意的是ARC下,没有栈block,尝试打印block对象,的确没有看到MallocBlock,但是通过clang反编译看到isa还是指向的_NSConcreteStackBlock。

结构

一个block其实是一个对象,有他自己的属性,结构如下

  • isa指针,所有对象都有该指针,用于实现消息传递等功能(ias一般指向父类、元类)
  • flags,用于按bit位表示一些block的附加信息
  • reserved,保留变量。
  • invoke,函数指针,指向具体的block实现的函数调用地址。
  • descriptor, 表示该block的附加描述信息,主要是size大小,以及copy和dispose函数的指针。
  • variables,capture过来的变量,block能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。

 

变量

block支持全局变量、静态变量、全局的函数、局部变量、封闭的参数,而且支持两种其他变量的类型__block修饰符(读写)、只读。

引用官方文档:

Within the block object’s body of code, variables may be treated in five different ways.

You can reference three standard types of variable, just as you would from a function:

  • Global variables, including static locals
  • Global functions (which aren’t technically variables)
  • Local variables and parameters from an enclosing scope

Blocks also support two other types of variable:

  1. At function level are __block variables. These are mutable within the block (and the enclosing scope) and are preserved if any referencing block is copied to the heap.
  2. const imports.

block变量使用规则:

  1. 全局变量,包括静态变量可以直接在block使用(block内可以直接修改,注意内存,会有强引用
  2. block参数传递,类似函数参数
  3. 存在栈上的变量(非静态的),即局部变量。这些变量将会被截获,他们将会被block引用,他们的值是在初始block之前截获最近的一次
  4. 定义在封闭区间的本地变量(局部变量),用__block修饰符,是可以修改的,任何的更改将会反应到封闭的区间,包括任何引用到的block
  5. block内部定义的变量,和函数内部定义的变量一样。

引用官方文档:

The following rules apply to variables used within a block:

  1. Global variables are accessible, including static variables that exist within the enclosing lexical scope.
  2. Parameters passed to the block are accessible (just like parameters to a function).
  3. Stack (non-static) variables local to the enclosing lexical scope are captured as const variables.Their values are taken at the point of the block expression within the program. In nested blocks, the value is captured from the nearest enclosing scope. 
  4. Variables local to the enclosing lexical scope declared with the __block storage modifier are provided by reference and so are mutable.Any changes are reflected in the enclosing lexical scope, including any other blocks defined within the same enclosing lexical scope. These are discussed in more detail in “The __block Storage Type.” 
  5. Local variables declared within the lexical scope of the block, which behave exactly like local variables in a function. Each invocation of the block provides a new copy of that variable. These variables can in turn be used as const or by-reference variables in blocks enclosed within the block.

后续会详细介绍block的各种变量使用。