代码块(block)
1. 代码块 (block)
block 类似于c语言的函数指针 但是比函数指针功能更强,是多种高级语言提供的"闭包"
2. 代码块的定义
代码块的定义和函数指针相似
//返回类型为void的block 定义一个block 返回类型不加括号
void(^myblock)(NSString*str);
//给block赋值
myBlock = ^(NSString *str) {
NSLog(@"%@", str);
};
//调用block
myBlock(@"测试!");
2.带返回类型的block
//定义了一个block, 注意:返回类型不能加括号
//定义block时,指明返回类型
//给block赋值
//注意^前面没有返回类型,通过block内部的return判定返回类型
myBlock = ^(NSString *str) {
str = [NSString stringWithFormat:@"收到:%@", str];
return str;
};
//调用block
NSString *value = myBlock(@"测试!");
NSLog(@"%@", value);
3 不带参参数的block 在给block 赋值的时候 如果不带参数,则等号右边是块定义可以省略参数列表 但是定义block变量时 即使没有参数也需要有()
void*(^myblock)();//没有参数的block
myblock= ^{
//执行的代码
}
myblcok();//调用block
4 定义的同时 初始化blcok
NSString *(^myBlock)(NSString*str)= ^(NSString*str){
str = [NSString stringWithFormat:@"%@",str];
return str;
}
//调用block
NSString *Value = myblock(@"测试数据");
NSlog(@"%@",Value);
3. 捕获
1 block内使用block定义体之外的变量
Nsstring* name = @"mybock";
NSString*(^myblock)(NSString*str) = ^(NSString*str){
str = [NSString stringWithFormat:@"%@%@",str,name];
return str;
};
//调用block
NSlog(@"%@",myblcok(@"测试数据"));
1 代码块内可以”捕获”代码块以外的变量
全局变量 block 内使用全局变量时 该 全局变量被捕获为变量
被捕获的全局变量变化时 block内的相应变量也会发生相应的变化
2 使用局部变量 block内使用局部变量 该局部变量捕获为常量
block 内的相变量不会发生变化
3 使用静态变量时 被捕获为 变量
4 使用指向oc对象的指针 如果该指针变量也被捕获为常量 但是指针所指向的对象是可以变化的
5 block 内捕获oc对象时 , 是强引用 可能产生循环引用 导致内存泄漏
@interface Car : NSObject
@property (nonatomic, copy) void (^myBlock) (void);
@property (nonatomic) float length;
@property (nonatomic) float width;
@property (nonatomic) float height;
- (instancetype)initWithLength:(float)length andWidth:(float)width andHeight:(float)height;
@end
这里写代码#import "Car.h"
@implementation Car
- (instancetype)initWithLength:(float)length andWidth:(float)width andHeight:(float)height
{
self = [super init];
if (self) {
_length = length;
_width = width;
_height = height;
}
return self;
}
- (NSString*) description
{
return [NSString stringWithFormat:@"%.2f,%.2f,%2.f", _length, _width, _height];
}
- (void)dealloc
{
NSLog(@"销毁汽车, %p", self);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *car = [Car new];
car.length = 5.4;
car.myBlock = ^{
NSLog(@"%@", car); //导致强“循环引用”
};
car.myBlock();
}
return 0;
}
解决方案 :
int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *car = [Car new];
car.length = 5.4;
__weak Car *car2 = car;
car.myBlock = ^{
NSLog(@"%@", car2);
};
car.myBlock();
}
return 0;
}
注意:block的参数,和普通函数的参数一样,每次执行时,根据参数的当前实际值处理。
nt a = 10;
int b = 20;
void (^testBlock)(int, int) = ^(int a, int b){
NSLog(@"%d", a+b);
};
testBlock(a, b); //30
a++;
testBlock(a, b); //31
- 使用__block
block内捕获局部变量时,被识别为“常量”,导致:
1)被捕获的局部变量的值变化时,block内对应的值不能改变。
2)在block内不能直接改变被捕获的变量的值。
如果强行改变,将无法通过编译。
解决方案:
使用__block, 即被捕获的局部变量使用__block特性进行修饰。
__block NSString *name = @"Lufy";
NSString* (^myBlock)(NSString *str) = ^(NSString *str) {
str = [NSString stringWithFormat:@"%@%@", str, name];
return str;
};
//调用block
NSLog(@"%@", myBlock(@"测试"));
name = @"Shanji";
NSLog(@"%@", myBlock(@"测试"));
- block作为函数的参数
用法类似于c语言中,使用函数指针实现回调
NSArray *array1 = @[@"Hello", @"world", @"good", @"morning"];
NSArray *array2 = [array1 sortedArrayUsingComparator:^(NSString *str1, NSString *str2) {
return [str1 compare:str2];
}];
或者使用block变量
NSArray *array1 = @[@"Hello", @"world", @"good", @"morning"];
NSComparisonResult (^compare)(NSString*, NSString*) = ^(NSString *str1, NSString *str2) {
return [str1 compare:str2];
};
NSArray *array2 = [array1 sortedArrayUsingComparator:compare];
- 使用typedef定义block类型
使用typedef可以使block变量的定义简化
NSString *name = @"Lufy";
typedef void (^myBlock_t)(NSString*);
myBlock_t myBlock = ^(NSString *act){
NSLog(@"%@, %@!", act, name);
};