初识Block

iOS三大回调方式:目标动作回调,委托回调,代码块回调。block最大的用处就是回调,可以代替委托。
Block:一段代码,相当于函数指针,指向一段代码的内存地址。可以访问外部作用域的变量,可用于回调。可以作为参数传递。

1.基础

1)定义
格式:(ReturnType) (^BlockName) (Args , Args2){}

1
2
3
4
int (^addBlock)(int a,int b) = ^(int a,int b){
return a + b;
};
addBlock(2,3);

定义一个名为addBlock的变量,需要两个参数。

1
2
3
void (^someBlock)() = ^{
//the block of code
};

Block无参数时,可以省略括号^{}.
2)创建块类型typedef

1
typedef  int  (^EOCSomeBlock) (BOOL flag, int value);

创建了一个名为EOCSomeBlock的类型

1
2
3
EOCSomeBlock   block =  ^(BOOL flag  , int  value ){
//some code
}

定义一个EOCSomeBlock类型的变量block
3)block 修饰可读写变量
block块内部可以获取在其声明范围的变量,但是只能读不能写。声明变量的时候加上
block修饰,就可以在块内修改该变量了。block代码分配在栈上,__block 将变量分配到堆上。

1
2
3
4
5
6
7
8
9
//简写,相当于[NSArray arrayWithObjects:[NSNumber numberWithInt:3],[NSNumber numberWithInt:5], nil];
NSArray *array = @[@3,@5,@6,@8,@13];
__block NSInteger count = 0;
//NSArray 枚举数组中每项
[array enumerateObjectsUsingBlock:^(NSNumber *number, NSUInteger idx,BOOL *stop){
if ([number compare:@2] == NSOrderedAscending) {
count++;
}
}];

4)weak 避免引用循环
将块定义在类的实例方法中,块内可以访问类的所有实例变量,还可以使用self变量。
在内存分配管理中,会有一个强指针指向block ,而block内部的self本身也有一个强指针指向block,就造成了强引用循环,双方都不能释放。
使用
weak创建弱引用变量,该变量指向的对象,当没有指针指向时,会设置为nil ,避免了引用环(retain cycle)

1
2
3
4
__weak MyClass *weakSelf = self;
[self.myBlocks addObject:^ {
[weakSelf doSomething];
}];

2.使用场景

1)枚举(数组,字典枚举每项),视图动画,排序
2)通知Notification
3)错误处理
4)多线程GCD(重要功能)
5)代替委托(delegate)功能