一、block简介
block代码块是在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,block是一种特殊的数据类型,其可以正常定义变量、作为参数、作为返回值,blcok还可以保存一段代码,在需要时调用。
二、block定义
block在定义时并不会执行内部的代码,只有在调用时才会执行。
//block变量的赋值:Block变量 = ^(参数列表){函数体};
1、无参数无返回值的block
//1、无参数无返回值的block
//zqqBlock是block名 无参数可省略参数列表()
//void (^zqqBlock)() = ^{};
void (^zqqBlock)() = ^(){
NSLog(@"这是无返回值无参数的block");
};
//调用
zqqBlock();
2、有参数无返回值的block
//zqqBlock是block名 NSString 是参数类型,x,y参数
void (^zqqBlock)(NSString* ,NSString*) = ^(NSString *x,NSString *y){
NSLog(@"这是无返回值有参数的block,参数是%@,%@",x,y);
};
//调用
zqqBlock(@"a",@"b");
3、有参数有返回值的block
//NSString是返回类型 zqqBlock是block名 NSString 是参数类型,x,y参数
NSString* (^zqqBlock)(NSString* ,NSString*) = ^(NSString *x,NSString *y){
return [NSString stringWithFormat:@"%@+%@",x,y];
};
//调用
NSString *testStr = zqqBlock(@"a",@"b");
NSLog(@"%@",testStr);
三、block使用
1、block重命名
利用typedef为block进行重命名
#import "ViewController.h"
@interface ViewController ()
//定义一个无返回值无参数的block
typedef void (^zqqBlock)();
//用自定义的zqqBlock声明一个block
@property (nonatomic, copy) zqqBlock abock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 避免循环引用,用__weak修饰
__weak ViewController *weakSelf = self;
self.abock = ^{
weakSelf.view.backgroundColor = [UIColor redColor];
};
//调用
self.abock();
}
@end
2、block的应用场景
block声明属性要用copy修饰
因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的
<栈 :由系统维护的局部变量 是存在栈上的,其生命周期随函数的生命周期>
<堆 :由程序员申请空间地址,由程序员手动释放,生命周期受到程序员控制>
使用retain也可以,因为block的retain行为默认是用copy的行为实现的,block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。
block的使用:
- 反向传值
//1.在NextViewController.h中声明block
#import <UIKit/UIKit.h>
typedef void (^popToNextBlock)(UIColor *color);//1.别名 传参
@interface NextViewController : UIViewController
@property (nonatomic, strong) popToNextBlock popToNextBlock;//2.声明block
@end
//2.在NextViewController.m中定义block
#import "NextViewController.h"
-(void)popToFirstBtnClick:(id)sender{
[self.navigationController popViewControllerAnimated:YES];
if (self.popToNextBlock){
UIColor *color = [UIColor redColor];
self.popToNextBlock(color);
}
}
//上一控制器push时调用
NextViewController *nextVc = [[NextViewController alloc]init];
[self.navigationController pushViewController:nextVc animated:YES];
//调用block
__weak ViewController *weakSelf = self;
//block的回调只对最后一次赋值有效
nextVc.popToNextBlock = ^(UIColor *color){
//避免循环引用,应该使用弱引用
weakSelf.view.backgroundColor = color;
};
- 在方法中定义block 回调传值
//1.ZqqTool.h文件
#import <Foundation/Foundation.h>
typedef void(^ZqqToolBlock)(NSString *string);
@interface ZqqTool : NSObject
//在方法中封装block
-(void)zqqToolWithString:(NSString *)str andBlock:(ZqqToolBlock)block;
//2.ZqqTool.m文件
#import "ZqqTool.h"
-(void)zqqToolWithString:(NSString *)str andBlock:(ZqqToolBlock)block{
block(str);
}
@end
//3.调用
ZqqTool *tool = [[ZqqTool alloc]init];
[tool zqqToolWithString:@"测试" andBlock:^(NSString *string) {
NSLog(@"%@",string);
}];
- 作为参数传递
//1.ZqqSendBlock ZqqTool.h文件
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef void(^ZqqSendBlock)(UIColor *color);
typedef void(^ZqqToolBlock)(NSString *string);
@interface ZqqTool : NSObject
//在方法中封装block
-(void)zqqToolWithString:(NSString *)str andBlock:(ZqqToolBlock)block;
-(void)ZqqSendBlock:(ZqqSendBlock)block;
@end
//2..ZqqTool.m文件
#import "ZqqTool.h"
@implementation ZqqTool
-(void)zqqToolWithString:(NSString *)str andBlock:(ZqqToolBlock)block{
block(str);
}
-(void)ZqqSendBlock:(ZqqSendBlock)block{
block([UIColor redColor]);
}
@end
//3.调用
ZqqTool *tool = [[ZqqTool alloc]init];
[tool zqqToolWithString:@"测试" andBlock:^(NSString *string) {
NSLog(@"%@",string);
}];
[tool ZqqSendBlock:^(UIColor *color) {
//
self.view.backgroundColor = color;
}];
注意:1、block中使用局部变量
局部变量在block中只读。变量的值在Block外改变,也不影响他在Block中的值。局部变量加__block修饰可在block代码块内被修改。
注意:2、block中循环引用问题
block用copy修饰,在self持有block中调用self或调用属于self的都会出现循环引用!解决方法:__weak Class *weakSelf = self;
而block本身不被self持有,就不会出现循环引用了。例如:UIView的动画block
[UIView animationWithDuration:0.2 animation:^{
//
}];
网友评论