Block 是iOS在4.0之后新增的程序语法,严格来说block的概念并不算是基础程序设计的范围,对初学者来说也不是很容易了解,但是在iOS SDK 4.0之后,block几乎出现在所有新版的API之中,换句话说,如果不了解block这个概念就无法使用SDK 4.0版本以后的新功能。
Block定义:
我们使用「^」运算符来表示一个block变量,而且在block的定义最后面要加上「;」来表示一个完整的语句,下面是一个block的例子:
int multiplier = 7 ;
int (^myBlock)( int ) = ^( int num)
{
return num * multiplier;
};
char *myCharacters[ 3 ] = { "TomJohn" , "George" , "Charles Condomine" };
qsort_b (myCharacters, 3 ,
sizeof ( char *),
^( const void *l, const void *r)//block部分
{
char *left = *( char **)l;
char *right = *( char **)r;
return strncmp (left, right, 1 );
} //end
);
一般来说,在block内只能读取在同一个作用域的变量而且没有办法修改在block外定义的任何变量,此时若我们想要这些变量能够在block中被修改,就必须在前面加上__block的修饰符,以上面第一个例子中的 multiplier 来说,这个变量在 block 中是只读的,所以 multiplier = 7 指定完后,在 block 中的 multiplier 就只能是 7 不能修改,若我们在 block 中修改 multiplier ,在编辑时就会产生错误,因此若想要在 block 中修改 multiplier ,就必须在 multiplier 前面加上 __block 的修饰词,请参考下面的例子:
__block int multiplier = 7 ;
int (^myBlock)( int ) = ^( int num)
{
if (num > 5 )
{
multiplier = 7 ;
}
else
{
multiplier = 10 ;
}
return num * multiplier;
};
Block的内存管理
block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。比如下面的例子。
我在view did load中创建了一个block:
- - (void)viewDidLoad
- {
- [superviewDidLoad];
- int number = 1;
- _block = ^(){
- NSLog(@number %d, number);
- };
- }
- - (IBAction)testDidClick:(id)sender {
- _block();
- }
- _block = ^(){
- NSLog(@number %d, number);
- };
- _block = [_blockcopy];
- [array addObject:[[^{
- NSLog(@hello!);
- } copy] autorelease]];
-
对于非ARC下, 为了防止循环引用, 我们使用__block来修饰在Block中使用的对象:
对于ARC下, 为了防止循环引用, 我们使用__weak来修饰在Block中使用的对象。原理就是:ARC中,Block中如果引用了__strong修饰符的自动变量,则相当于Block对该变量的引用计数+1。
这一点其实是在第一点的一个小的衍生。当在block内部使用成员变量的时候,比如
- @interface ViewController : UIViewController
- {
- NSString *_string;
- }
- @end
在block创建中:
- _block = ^(){
- NSLog(@string %@, _string);
- };
修改方案是新建一个__block scope的局部变量,并把self赋值给它,而在block内部则使用这个局部变量来进行取值。因为__block标记的变量是不会被自动retain的。
__block ViewController *controller = self;
_block = ^(){
NSLog(@string %@, controller->_string);
};