block的使用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了block的使用相关的知识,希望对你有一定的参考价值。
参考技术A 带有自动变量(局部变量)的 匿名函数 。这个定义满足以下三点: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
Block的使用--初探Block
看了两天的Block。
网上是有非常多解说与教程,也有讲得非常好的。这里就主要解说下我的理解与收获。欢迎拍砖。
所谓block。我觉得应该是一个闭包函数。而闭包,就是说block以及内部全部的变量生命周期都在其调用函数的生命周期内。
它一被调用完毕,则会被立刻释放。这里不讲运行机制,仅仅简要地讲基本的用法(这里所讲是基于ARC的环境下)。
定义以及使用
1、放在函数体内的Block:生命周期:仅仅存在于函数体。与函数体内的局部变量相似。
其定义方式跟函数还是非常相似的。为了简便理解我们对照下block与函数的定义。先看一下最简单的形式,无返回值带參。先看Block直接放在函数体内的形式:
函数:
- (void)printBlock:(NSString *)output {
NSLog(@"output == %@", output);
}
Block直接放在函数体内的形式:
void(^printBlock)(NSString *) = ^(NSString *output)
{
NSLog(@"output == %@", output);
};
这里能够看到。我们的函数体一般形式是:
- (返回值) 函数名: (形參)...
调用形式是:[调用对象 函数名(形參)];
那我们放在函数体内的Block定义则是:
返回值 (^ Block名)( 形參 ) = ^( 形參 ){ //实现内容 };
调用形式是 :Block名(形參)。
这里的Block就相当于是一个内嵌函数。
声明与实现要同一时候放在一起。形式就非常像我们寻常使用的对象赋值一样:id obj = ... ;
2、放在函数外的Block。
即为类内部范围内的全局Block。生命周期为整个类内部。
定义与用法都与上面一致,仅仅只是就像局部变量与类变量一样是否可被其它方法调用而已。为了更简单明了我们能够看一下这个代码:
//普通方法定义
- (void)printBlock:(NSString *)output {
NSLog(@"output == %@", output);
}
//函数体外的Block
void(^printBlock)(NSString *) = ^(NSString *output)
{
NSLog(@"output == %@", output);
};
//Block调用
- (void)printSomething {
printBlock(@"I‘m printBlock");
}
3、放在类定义头文件的Block。
可被实例对象拥有。生命周期为整个实例对象。
头文件里的定义(1):
typedef void(^printBlockClass)(NSString *);
@interface BlockClass : NSObject
@property (nonatomic, copy)printBlockClass print;
@end
//或者在实现文件里:
//但这样的实如今内部的Block我也不知道有什么卵用。实际应用不大。
@interface BlockClass : NSObject
{
printBlockClass print;
}
@end
头文件里的定义(2):
//与方式一的差别无非像是自己定义一种结构然后你再去使用一样
@interface BlockClass : NSObject
@property (nonatomic, copy) void(^printBlockClass)(NSSting *output);
@end
这样的把Block作为属性的情况是比較多用于页面传值中。
关于Block的使用另一下几个注意点:
1、仅仅有在调用Block的时候才会运行{}内部的代码(就比方把Block定义在函数体内不调用是不会运行的)。
2、在Block的{}内部代码中是对外部的变量能够引用,但不能改变。假设试图更改会产生一个编译器错误。除非你把想要更改的变量声明时加上 __block关键字。
3、在block使用过程要注意不要产生循环引用。
关于循环引用(Memory Recycle)这里有一篇文章写得不错。有兴趣能够看看:http://blog.csdn.net/fengsh998/article/details/38090205
以上是关于block的使用的主要内容,如果未能解决你的问题,请参考以下文章