使用^操作符来来声明一个block变量和指示block文本的开始。Block本身的主体被{}包含着,如下面的例子那样(通常使用 C 的;符合指示block的结束):
int (^myBlock)(int) = ^(int num){
return 10*num;
};
NSLog(@"%d",myBlock(2));
下面是官方对block的经典解释
Block功能
一个 block就是一个匿名的内联代码集合体:
1.和函数一样拥有参数类型
2.有推断和声明的返回类型
3.可以捕获它的声明所在相同作用域的状态
4.可以和其他定义在相同作用域范围的 blocks 进行共享更改
5.在相同作用域范围(栈帧)被销毁后持续共享和更改相同作用域范围(栈帧)的状态
你可以拷贝一个 block,甚至可以把它作为可执行路径传递给其他线程(或者在自己的线程内传递给run loop)。编译器和运行时会在整个block生命周期里面为所有block引用变量保留一个副本。尽管blocks在纯 C 和 C++上面可用,但是一个block也同样是一个Objective-C的对象。
Block用处
Blocks通常代表一个很小、自包的代码片段。因此它们作为封装的工作单元在并发执行,或在一个集合项上,或当其他操作完成时的回调的时候非常实用。
Blocks作为传统回调函数的一个实用的替代办法,有以下两个原因:
1.它们可以让你在调用的地方编写代码实现后面将要执行的操作。因此 Blocks通常作为框架方法的参数。
2.它们允许你访问局部变量。而不是需要使用一个你想要执行操作时集成所有上下文的信息的数据结构来进行回调,你可以直接简单的访问局部变量。
你同样可以创建 blocks的类型。当你在多个地方使用同一个给定的签名的block时,这通常被认为是最佳的办法
typedef float (^MyBlockType)(float, float);
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;
Block的闭包性(closure)
在block内部,可以像普通函数一样访问数据:局部变量、传递给block的参数,全局变量/函数。并且由于block具有闭包性,所以还能访问非局部变量(non-local variable)。非局部变量定义在block之外,但是在block内部有它的作用域。例如,getFullCarName可以使用定义在block前面的make变量:
NSString *make = @"Honda";
NSString *(^getFullCarName)(NSString *) = ^(NSString *model) {
return [make stringByAppendingFormat:@" %@", model];
};
NSLog(@"%@", getFullCarName(@"Accord")); // Honda Accord
非局部变量会以const变量被拷贝并存储到block中,也就是说block对其是只读的。如果尝试在block内部给make变量赋值,会抛出编译器错误。
以const拷贝的方式访问非局部变量,意味着block实际上并不是真正的访问了非局部变量——只不过在block中创建了非局部变量的一个快照。当定义block时,无论非局部变量的值是什么,都将被冻结,并且block会一直使用这个值,即使在之后的代码中修改了非局部变量的值。下面通过代码来看看,在创建好block之后,修改make变量的值,会发生什么:
NSString *make = @"Honda";
NSString *(^getFullCarName)(NSString *) = ^(NSString *model) {
return [make stringByAppendingFormat:@" %@", model];
};
NSLog(@"%@", getFullCarName(@"Accord")); // Honda Accord
// Try changing the non-local variable (it won't change the block)
make = @"Porsche";
NSLog(@"%@", getFullCarName(@"911 Turbo")); // Honda 911 Turbo
修改非局部变量
冻结中的非局部变量是一个常量值,这也是一种默认的安全行为——因为这可以防止在block中的代码对非局部变量做了意外的修改。那么如果我们希望在block中对非局部变量值进行修改要如何做呢——用__block存储修饰符(storage modifier)来声明非局部变量:
__block NSString *make = @"Honda";
通过引用的方式访问非局部变量
这跟普通函数中的静态局部变量(static local variable)类似,用__block修饰符声明的变量可以记录着block多次调用的结果。例如下面的代码创建了一个block,在block中对i进行累加。
__block int i = 0;
int (^count)(void) = ^ {
i += 1;
return i;
};
NSLog(@"%d", count()); // 1
NSLog(@"%d", count()); // 2
NSLog(@"%d", count()); // 3
闭包性这个概念是允许一个函数访问其所声明上下文中的变量,甚至是在不同的运行上下文中。
主动调用一下:
- (void)someMethod
{
BoolBlock ablock = ^(BOOL bValue) {
NSLog(@"Bool block!");
};
ablock();
}
作为参数返回:
typedef void (^BoolBlock)(BOOL);
- (BoolBlock)foo()
{
BoolBlock ablock = ^(BOOL bValue) {
NSLog(@"Bool block!");
};
return [[ablock copy] autorelease];//一定要copy,将其复制到堆上,更详细的原理,将在后续章节讲解
}
类的一个成员:
@interface OBJ1 : NSObject
@property (nonatomic, copy)BoolBlock block;//理由同上啊,同学们
@end
OBJ1 *obj1 = ...
obj1.block = ^(BOOL bValue) {
NSLog(@"Bool block!");
};
其他函数的参数:
- (void)foo(BoolBlock block)
{
if (block) {
block();
}
}
甚至其他block的参数:
BoolBlock bBlock = ^(BOOL bV){if(Bv){/*do some thing*/}};
HugeBlock hBlock = ^(BoolBlock bB) {bB();};
hBolck(bBlock);
全局变量!:
static int(^maxIntBlock)(int, int) = ^(int a, int b){return a>b?a:b;};
int main()
{
printf("%d\n", maxIntBlock(2,10));
return 0;
}
用block进行传值VC1.H
@interface ViewController : UIViewController
@property(nonatomic, strong)UILabel *label;
@property(nonatomic, strong)UIButton *btn;
@end
VC1.M
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor yellowColor];
self.label = [[UILabel alloc]initWithFrame:CGRectMake(50, 50, 100, 50)];
self.label.backgroundColor = [UIColor brownColor];
[self.view addSubview:self.label];
self.btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.btn.frame = CGRectMake(50, 250, 100, 50);
self.btn.backgroundColor = [UIColor grayColor];
[self.btn addTarget:self action:@selector(push) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.btn];
}
- (void)push{
ViewController2* second = [[ViewController2 alloc] init];
second.callback = ^(NSString *msg){
self.label.text = msg;
};
[self.navigationController pushViewController:second animated:YES];
}
VC2.H
#import <UIKit/UIKit.h>
@interface ViewController2 : UIViewController
@property(nonatomic, strong)UIButton *btn;
@property(strong,nonatomic) void (^callback) (NSString* _msg);
@end
VC2.M
- (void)viewDidLoad
{
[super viewDidLoad];
self.btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.btn.frame = CGRectMake(50, 250, 100, 50);
self.btn.backgroundColor = [UIColor grayColor];
[self.btn addTarget:self action:@selector(pop) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.btn];
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn2.frame = CGRectMake(50, 170, 100, 50);
btn2.backgroundColor = [UIColor blueColor];
[btn2 addTarget:self action:@selector(send) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn2];
}
- (void)send{
if (_callback) {
_callback(@"123");
_callback = nil;
}
}
- (void)pop{
[self.navigationController popViewControllerAnimated:YES];
}
block放在哪里 ---- IOS中堆和栈的区别
void foo()
{
__block int i = 1024;
int j = 1;
void (^blk)(void);
void (^blkInHeap)(void);
blk = ^{ printf("%d, %d\n", i, j);};//blk在栈里
blkInHeap = Block_copy(blk);//blkInHeap在堆里
}
- (void)fooBar
{
_oi = 1;
OBJ1* oj = self;
void (^oblk)(void) = ^{ printf("%d\n", oj.oi);};
void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中
}
#import <UIKit/UIKit.h>
@interface AppDelegate : NSObject <UIApplicationDelegate>
@property (nonatomic, strong) NSString *stringProperty;
@end
#import "GCDAppDelegate.h"
@implementation AppDelegate
@synthesize stringProperty;
- (void) BlockTestError{
HelloBlock myBlock= ^(void){
self.stringProperty = @"Block Objects";
NSLog(@"String property = %@", self.stringProperty);//运行错误
};
myBlock();
}}
- (void) BlockTestCorrect{
HelloBlock myBlock= ^(void){
[self setStringProperty:@"Block Objects"];
NSLog(@"self.stringProperty = %@", [self stringProperty]); //运行ok
};
myBlock();
}}
@end
参考文章: Block教程系列 初识block block传值 ios开发--block应该知道的那几件事