一、block(块)的定义
block是一种类型,封装了一段代码块,可以在任何时候执行,block也可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。block与函数类似,只不过是直接定义在另一个函数里,和定义它的那个函数共享同一个范围内的东西。block用“^”符号来表示,后面跟着一对花括号,括号里面是block的实现代码,例如
^{
// block的代码实现
}
二、block的使用
1、不带参数,空返回值的block
int num = 100;
__block int num1;
//不带参数,空返回值
void(^MyBlock)() = ^()
{
NSLog(@"----");
NSLog(@"----");
//num =10; block中不能修改局部变量
NSLog(@"---%d---",num);
num1 = 30;
NSLog(@"---%d---",num1);
};
MyBlock();
block能捕获变量,但不能在block中修改变量,不过如果在声明变量的时候加上__block修饰符,这样就可以在block中修改了。
2、带参数,空返回值的block
void(^LineBlock)(int)= ^(int n)
{
for(int i =0;i<n;i++)
{
NSLog(@"+++++++");
}
};
LineBlock(9);
3、有返回值,带多个参数
int(^SumBlock)(int,int) = ^(int a,int b)
{
return a+b;
};
int sum = SumBlock(9,10);
NSLog(@"sum = %d",sum);
4、用typedef定义类型
//用typedef声明类型再定义变量
typedef int(^MyMathBlock)(int,int);
MyMathBlock minus = ^(int a,int b)
{
return a-b;
};
NSLog(@"minus = %d",minus(11,9));
5、block与指针函数对比
//定义一个函数
int sum3(int a,int b)
{
return a+b;
}
/*
指针函数
*/
int (*p)(int,int) = sum3;
NSLog(@"函数指针使用 sum=%d",p(100,20));
typedef类型的函数
typedef int(*myMath)(int,int);
myMath p1 = sum3;
NSLog(@"函数指针和typedef的使用 sum=%d",p1(1000,20));
6、inline block(内联块)
/*
*计算数组中等于2的个数
*NSOrderedAscending:The left operand is smaller than the right operand(左边小于右边)
*NSOrderedDescending:The left operand is greater than the right operand(左边大于右边)
*NSOrderedSame:The two operands are equal(相等)
*/
NSArray * array = @[@0,@1,@2,@3,@4,@5,@6];
__block NSUInteger count = 0;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj compare:@2] == NSOrderedSame) {
count++;
}
}];
NSLog(@"count = %ld",count);
return 0;
三、block(块)的深入
如果块所捕获的变量是对象类型,那么就会自动保留它。系统在释放这个块的时候,也会将其一并释放。其实块本事可视为对象,块本身也和其他对象一样,有引用计数,当最后一个指向块的引用移走后,块就被回收了,回收时也会释放块所捕获的变量,以便平衡捕获时所执行的保留操作
如果将块定义在类的实例方法中,那么除了可以访问类的所有实例变量外,还可以使用self变量。块定义在类中总能修改实例变量,所以声明时无需加__block。当通过读取或写入操作捕获了实例变量,那么也会自动把self变量一并捕获,因为实例变量与self所指代的实例关联在一起的。例如有个Person类
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,assign) int age;
- (void)anInstanceMethod;
@end
#import "Person.h"
@implementation Person
- (void)anInstanceMethod
{
void(^someBlock)() = ^{
_age = 10;
NSLog(@"age = %d",_age);
};
someBlock();
}
@end
#import <Foundation/Foundation.h>
#import "Person.h"
int main()
{
Person *p = [[Person alloc] init];
[p anInstanceMethod];
return 0;
}
该代码的执行结果为:
如果Person类的某个实例正在执行anInstanceMethod方法,那么self变量就指向此实例,所以也可以通过self来访问实例变量
例如:self->_age = 10; 或者是 self.age = 10;