一 代码块的语法
代码块的书写和C语言函数的语法格式有点像,例如下面求和函数分别用C 语言和代码块来实现:
int add(int a,int b)
{
return a+b;
}
int (^add)(int a,int b) = ^(int a,int b) { return a +b; };
注意:a.代码块最后的大括号后面一定要加分号。
b.与c语言的函数签名不同的是,代码块的名字需要用'^'和括号。
c. 代码块的签名部分和实现部分需要用'=^(参数列表)'来连接。
除次之外代码块还可以将签名和实现部分分开来实现,例如:
void (^PrintInfo)(NSString *info); PrintInfo = ^(NSString *info) { NSLog(@"%@",info); };
代码块也可以看作是函数的指针,差别是用^代替了*.
二 代码块的调用方式
1.直接调用,例如,对于刚才定义的PrintInfo代码块
PrintInfo(
@"Hello World"
);
2.使用代码块"指针"的方式来实现,例如:
typedef void (^Print) (NSString *info);
void (^PrintName) (NSString * name) = ^(NSString * name) { NSLog(@"MyName:%@",name); }; Print myBlock = PrintName; myBlock(@"Hello"); void (^PrintCountry)(NSString * Country)= ^(NSString *Country) { NSLog(@"MyCountry:%@",Country); }; myBlock= PrintCountry; myBlock(@"China");
注: 在一个block的内部可以调用另外一个block
/*************** Definition of first block object ***************/
NSString *(^trimString)(NSString *) = ^(NSString *inputString)
{ NSString *result = [inputString stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceCharacterSet]]; return result; };/*************** Definition of second block object ***************/
NSString *(^trimWithOtherBlock)(NSString *) = ^(NSString *inputString)
{ return trimString(inputString);
}
3.使用方法举例
代码块的作用主要是用来做回调函数来使用的,它可以代替IOS SDK中的代理方法。使用代码块比用代理
方法的效率更高。
a.首先定义两个代码块指针
typedef void (^SucceedBlock)(void); //访问服务器成功的时候typedef void (^FailedBlock )(void); //访问服务器失败的时候 b.定义访问服务器方法 - (void) getDataFromServer:(NSString*) URL succeedBlock:(SucceedBlock) succeed
failedBlock:(FailedBlock) fail {
//模拟调用成功和失败 if ([URL isEqualToString:@"YES"]) { succeed(); } else { fail(); } }
c.调用上面的方法
void (^succeedBlock)(void) = ^ { NSLog(@"do something succeed thing"); };void (^failedBlock)(void) = ^ { NSLog(@"do some failed thing"); };
采用独立代码块的方式实现函数的调用
[self getDataFromServer:@"YES" succeedBlock:succeedBlock failedBlock:failedBlock];
也可以在调用的时候来定义代码块(内联的方式实现代码块的调用)
[
self getDataFromServer:@"NO" succeedBlock:^{ NSLog(@"inline succeed block!"); }failedBlock:^{ NSLog(@"inline failed block!");
}
];
d.直接用代码块作参数
-(void) testBlock:(NSString*)name completionBlock:(void (^)(NSString* addr)) block { block(name);
}
[self testBlock:@"zhangzhe" completionBlock:^(NSString *addr) {
NSLog(@"addr:%@",addr);
}];
四 代码块中变量访问
a.对于独立代码块,内部定义的局部变量的使用方式和普通的objective-c函数是相同的,可以进行读写
void (^independentBlockObject)(void) = ^(void)
{ NSInteger localInteger = 10; NSLog(@"local integer = %ld", (long)localInteger);
lojalitetger = 20; NSLog(@"local integer = %ld", (long)localInteger); };
localInteger是可以被读写的
b.对于内联方式定义的代码块,局部变量不仅包括在代码块内部定义的变量,而且还包含在实现代码块
函数内部定义的变量。对于前一部分变量是可读写的,对于后一部分变量是只读的。例如:
- (void)viewDidLoad
{
int outsideInteger = 10;
[self getDataFromServer:@"NO" succeedBlock:^{ int insideInteger = 10; ++insideInteger; //outsideInteger = 5; //这样直接写会报错误 提示outsideInteger没有加__block NSLog(@"ousideInteger=%d insideInteger=%d",outsideInteger,insideInteger); }failedBlock:^{ NSLog(@"inline failed block!"); }];
}
所以对于代码块外定义的局部变量是只读的,要想可以读写需要在改变量前面加两个下划线+block
__block
int outsideInteger = 10;
c.对于selfl变量的访问,如果是在独立代码块不能直接访问self变量,要访问可以将其作为代码块参数传入,对于内联点名块,只要在实现该代码块的函数可以访问的话,在代码块内部就可以直接访问。
void (^correctBlockObject)(id) = ^(id self)
{ NSLog(@"self = %@", self);
};
- (void)viewDidLoad
{
[self getDataFromServer:@"NO" succeedBlock:^{ NSlog(@"self = %@",self); }failedBlock:^{ NSLog(@"inline failed block!"); }];
}
d.对于使用 @property定义的属性变量的访问,如果内联代码块可以使用点号的方式访问,也可以使用
方括号的方式来访问,但是对于独立代码块的话只能使用后者来访问。
@interface GASSViewController : UIViewController
@property(nonatomic,strong) NSString *name;
@end
对于独立代码块
void (^correctBlockObject)(id) = ^(id self)
{
NSLog(@"self = %@", self); /* Should use setter method instead of this */ self.name = @"Block Objects"; /* Compile-time Error */ /* Should use getter method instead of this */ NSLog(@"self.name = %@",self.name); /* Compile-time Error */
};
对于内联代码块
[self getDataFromServer:@"NO" succeedBlock:^{ NSLog(@"self.name = %@",self.name); }failedBlock:^{ NSLog(@"inline failed block!");
}];
e.对于代码块外的变量,代码块会拷贝到自己的一个结构体内(相当于深拷贝),需要注意的是这个深拷贝是在定义代码块的时候进行的,而不是你调用的时候。
typedef void (^BlockWithNoParams)(void);
- (void) scopeTest
{
NSUInteger integerValue = 10; /*************** Definition of internal block object ***************/
BlockWithNoParams myBlock = ^{ NSLog(@"Integer value inside the block = %lu", (unsigned long)integerValue); }; /*************** End definition of internal block object ***************/ integerValue = 20; /* Call the block here after changing the value of the integerValue variable */ myBlock(); NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue); }
输出的结果:
Integer value inside the block = 10
Integer value outside the block = 20
避免这种情况
- (void) scopeTest
{
__block NSUInteger integerValue = 10; /*************** Definition of internal block object ***************/
BlockWithNoParams myBlock = ^{ NSLog(@"Integer value inside the block = %lu", (unsigned long)integerValue); }; /*************** End definition of internal block object ***************/ integerValue = 20; /* Call the block here after changing the value of the integerValue variable */ myBlock(); NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue);
}
输出的结果:
Integer value inside the block = 20
Integer value outside the block = 20
d.对于类中的实例成员来说,在代码块中可以直接访问是可以读写的,不用写__block
@interface GASSViewController ()
@property(nonatomic,strong) NSArray *testArr; @end
@implementation GASSViewController @synthesize testArr = _testArr;
void (^independentBlockObject)(void) = ^(void) { self.testArr = @[@"ONE",@"TWO"]; };
independentBlockObject();