1、定义面试
(1) Block是OC中的一种数据类型,在iOS开发中被普遍使用数组
(2) ^是Block的特有标记函数
(3) Block的实现代码包含在{}之间atom
(4) 大多状况下,之内联inline函数的方式被定义和使用指针
(5) Block与C语言的函数指针有些类似,但使用起来更加灵活对象
例如:作用域
void(^demoBlock)() = ^ {开发
NSLog(@"demo Block");编译
};table
int(^sumBlock)(int, int) = ^(int x, int y) {
return x + y;
};
格式说明:
(返回类型)(^块名称)(参数类型) = ^(参数列表) {代码实现};
若是没有参数,等号后面参数列表的()能够省略
2、常见相关面试题
Block可使用在定义以前声明的局部变量:
int i = 10;
void(^myBlock)() = ^{
NSLog(@"%d", i);
};
i = 100;//实际上并没效果
myBlock();
输出结果为:10
注意:
(1) 在定义Block时,会在Block中创建当前局部变量内容的副本(拷贝)
(2) 后续再对该变量的数值进行修改,不会影响Block中的数值
(3) 若是须要在block中保持局部变量的数值变化,须要使用__block关键字
(4) 使用__block关键字后,一样能够在Block中修改该变量的数值
3、当作参数传递
Block能够被当作参数直接传递:
NSArray *array = @[@"张三", @"李四", @"王五", @"赵六"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"第 %d 项内容是 %@", (int)idx, obj);
if ([@"王五" isEqualToString:obj]) {
*stop = YES;
}
}];
说明:遍历并NSLog() array中的内容,当obj 为"王五"时中止遍历
4、使用局部变量
在被当作参数传递时,Block一样可使用在定义以前声明的局部变量:
int stopIndex = 1;
NSArray *array = @[@"张三", @"李四", @"王五", @"赵六"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"第 %d 项内容是 %@", (int)idx, obj);
if ([@"王五" isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
}
}];
注意,默认状况下,Block外部的变量,在Block中是只读的!
BOOL flag = NO;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([@"王五" isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
flag = YES; // 编译错误!!!
}
}];
5、__block关键字
若是要修改Block以外的局部变量,须要使用__block关键字
__block BOOL flag = NO;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([@"王五" isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
flag = YES; // 如今能够修改了!!!
}
}];
提示:无需使用__block关键字,在块代码中能够修改为员变量的数值(比较少用)
6、传递对象
对象传递进Block的方式
NSString *stopName = @"王五";
NSArray *array = @[@"张三", @"李四", @"王五", @"赵六"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"第%d项内容是%@", (int)idx, obj);
if ([stopName isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
}
}];
为保证Block中的代码正常运行,在将stopName的指针传递给Block时,Block会自动对stopName的指针作强引用
7、Block在栈区工做示意图
8、typedef
可使用typedef定义一个Block的类型,便于在后续直接使用
typedef double(^MyBlock)(double, double);
MyBlock area = ^(double x, double y) {
return x * y;
};
MyBlock sum = ^(double a, double b) {
return a + b;
};
NSLog(@"%.2f", area(10.0, 20.0));
NSLog(@"%.2f", sum(10.0, 20.0));
说明:
(1) typedef是关键字用于定义类型,MyBlock是定义的Block类型
(2) area、sum分别是MyBlock类型的两个Block变量。
尽管,typedef能够简化Block的定义,但在实际开发中并不会频繁使用typedef关键字。
这是由于Block具备很是强的灵活性,尤为在以参数传递时,使用Block的目的就是为了当即使用。
官方的数组遍历方法声明以下:
而若是使用typedef,则须要:
(1) typedef void(^EnumerateBlock)(id obj, NSUInteger idx, BOOL *stop);
(2) - (void)enumerateObjectsUsingBlock:(EnumerateBlock)block;
而最终的结果倒是,除了定义类型以外,EnumerateBlock并无其余用处。
9、添加到数组
既然Block是一种数据类型,那么能够将Block当作比较特殊的对象
#pragma mark 定义并添加到数组
@property (nonatomic, strong) NSMutableArray *myBlocks;
int(^sum)(int, int) = ^(int x, int y) {
return [self sum:x y:y];
};
[self.myBlocks addObject:sum];
int(^area)(int, int) = ^(int x, int y) {
return [self area:x y:y];
};
[self.myBlocks addObject:area];
#pragma mark 调用保存在数组中的Block
int(^func)(int, int) = self.myBlocks[index];
return func(x, y);
10、循环引用
@property (nonatomic, strong) NSMutableArray *myBlocks;
#pragma mark 将代码改成调用self的方法
int(^sum)(int, int) = ^(int x, int y) {
return [self sum:x y:y];
};
[self.myBlocks addObject:sum];
#pragma mark 对象被释放时自动调用
- (void)dealloc
{
NSLog(@"DemoObj被释放");
}
十一、解除循环引用
局部变量默认都是强引用的,离开其所在的做用域以后就会被释放。
使用__weak关键字,能够将局部变量声明为弱引用
__weak DemoObj *weakSelf = self;
在Block中引用weakSelf,则Block不会再对self作强引用
int(^sum)(int, int) = ^(int x, int y) {
return [weakSelf sum:x y:y];
};