Objective-c编程-Blocks概要

Blocks是c语言的扩充功能,进行概述的话就是:带有局部变量的匿名函数。所谓匿名函数就是不带有名称的函数。标准的c语言是不允许这种函数的。

int func(int count)

它声明了一个名称为func的函数,在源代码中为乐调用该函数,必须使用该函数的名称func:

int result=func(10); 
//如果使用函数指针来代替直接调用函数,那么似乎不用知道函数名也能够使用该函数
int result=(*funcptr)(10);

但是如果深入了解的话,这种方式还是需要知道函数名称的,其具体源代码是下面这种方式;

int  (*funcptr)(int)=$func;
int result=(*funcptr)(10);

而通过blocks的话,源代码中能够使用匿名函数,即不带名称的函数,那么到底“带有的局部变量”到底是什么?

在c语言函数中可能使用的变量。

局部变量,函数的参数,静态变量,静态全局变量,全局变量,其中,在函数的多次调用之间能够传递值的变量有:

静态变量,静态全局变量,全局变量。

虽然这些变量的作用域不同,但是在整个程序当中,一个变量总保持在一个内存区域,因此虽然多次调用函数,但是该变量值总能保持不变,在任何时候以任何状态调用,使用的都是同样的变量值。

c++和oc可以使用类保持变量值并且能够多次持有变量自身,他会声明持有成员变量的类,它会声明持有成员变量的类,由类生成的实例活着对象保持该成员变量的值。

blocks提供了类似由c++和oc类生成实例或对象来保持变量值的方法。

Blocks模式

Block语法,即Block表达式语法,

^void (int event){

printf("buttonId:%d  event=%d\n",i,event);
}

这个完整的blocks语法与c语言函数的区别仅仅只有两点:

1 没有函数名。

2 带有“^”;

Block语法:我们可以在使用下面多种方法来声明blocks:

^ 返回值类型  参数列表  表达式 这是完整的声明语法

^返回类型    参数列表  表达式

^(int count){
return count+1;
}

^表达式

 

^{return count;}

 

Blocks类型变量

在block语法下,就相当于生成了可赋值的Block类型变量的值,Blocks中由Block语法生成的值也被称为"Block",

生成block类型变量的示例如下:

int (^blk)(int)//blk是这个block变量的变量名。

与前面的使用函数指针的源代码对比可知,声明block类型变量仅仅是将声明函数指针类型变量的"*"转换成"^",该block类型变量与一般c语言变量完全相同,可以作为下面各种用途:

局部变量,函数参数,静态变量,静态全局变量,全局变量。

我们将Block语法将Block赋值为block类型变量。

int (^blk)(int)=^(int count){return count+1}

由^开始的block语法生成的block被赋值给变量blk中,因为与通常的变量相同,所以当然也可以由block类型变量向block类型变量赋值。

int(^blk1)(int)=blk;
int(^blk2)(int);
blk2=blk1;

在函数参数中使用block类型变量可以向函数传递block.

int func(int (^blk)(int)){};

在函数返回值中指定block类型,可以将block作为函数类型返回。

int (^func)(int){return ^(int count){return count+1};

在函数参数和返回值中使用block类型变量时,记述方式极为复杂,这时我们可以像使用函数指针类型那样,使用typedef来解决该问题。

typedef int (^blk_t)(int);

我们使用通过typedef可声明"blk_t"类型变量。

void func(int (^blk)(int))//原来的记述方式
//采用typedef的记述方式
void func(blk_t blk){}

//原来的记述方式
int (^func()(int));
//现在的记述方式
blk_t blk;

将赋值给block类型变量中的block方法像c语言通常的函数调用那样使用,这种方法与使用函数指针类型变量调用函数的方法完全相同。

下面尽享一下对比:

int result=(*funcptr)(10);
//变量blk为block类型的情况下,使用下面方式
int result=blk(10);

通过block类型变量调用block与c语言通常的函数调用没有区别,在函数参数中使用block类型变量并在函数中执行BLOCK的例子。

-(int)method:blk_t blk,rate:(int)rate{
return blk(rate);
}

block类型变量可完全像c语言那样使用,因此也可以指向BLOCK类型变量的指针,即block的指针类型变量。

typedef int (^blk_t)(int);

blk_t blk=^(int count){return+1};

blk_t *blkptr=&blk;
(*blkptr)(10);

 

截获自动变量值

通过上面的说明,我们暂时理解了“带有自动变量的匿名函数”的函数,那么到底什么是“自动变量”,

block表达式基本上都是会截获保存自动变量的瞬时值,因为block表达式保存了自动变量的值,所以在执行block语法之后,即使改变了block中使用的自动变量的值也不会影响自动变量执行时候的值。

__block说明符

自动变量值截获职能保存执行block语法瞬间的值,保存之后就不能改写该值如果我们尝试去修改该值就会出现错误,如果我们想要在block语法中将赋值给block语法外声明的自动变量,需要在该自动变量上附加__block说明符,就可以实现在block内部进行赋值。附有__block说明符的自动变量可在block中进行赋值,该变量称为_block变量。

如果截获的是oc对象,调用变更该对象的方法编译的时候会出现什么情况。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
      __block  int val=0;
        void (^blk)(void)=^{ val=1;
        NSLog(@"%d",val);};
    
        blk();
        id  array=[[NSMutableArray  alloc]init];
        void (^blk1)(void)=^{
            id obj=[[NSObject alloc]init];
            [array addObject:obj];
        };
        blk1();
       /* void(^blk2)(void)=^{
            array=[[NSMutableArray  alloc]init];
        };*/
        //这种情况下就会出现问题 必须在前面加上__block
    }
    return 0;
}

自己的理解是有没有改变指针,指向的到底是不是原始的对象,如果是原始的对象,那么就不会出现异常,如果又重新赋值给新的的话,就必须在前面加上__block.

 

posted @ 2016-03-23 17:01  故园的梨花  阅读(297)  评论(0)    收藏  举报