一、Block简介
Block是ios4.0引入的基于c语言函数的一种回调机制,也可以说Block是带有自动变量(局部变量)的匿名函数。具体block是怎么实现的可以去看 唐巧的博文
二、Block的使用
1、Block类型
- 无参数无返回值的Block
- 有参数无返回值的Block
- 有参数有返回值的Block
2、创建Block
- 单独定义:返回值类型(^block变量名)(形参列表) = ^(形参列表) {};
- 调用:block变量名(实参);
- 作为OC方法参数的定义:返回值类型(^)(参数列表)block变量名
例:int (^myBlock)(int a, int b) = ^(int x, int y){
return x + y;
}
myBlock(a,b);//跟C语言调用函数一样
- (void)method:(void(^)()myBlock){};//block作为参数
3、Block注意事项
- Block是放在内存堆里面的
- Block不是对象,所以Block作为属性需要使用copy修饰
- 默认情况下,Block内部不能修改外面的局部变量
- Block内部可以修改使用__block修饰的局部变量
int num = 10;
__block int value = 10
void (^myBlock)(int a) = ^(int y){
num = 20;
value = 20;
};//
myBlock();
NSLog(@"num == %d value == %d",num,value);//这里num = 10;value = 20;
3、Block的具体使用
1、界面传值
使用block进行两个界面的传值,代码比起代理来说简洁很多。下面的代码是连个控制器之间的传值,当TowController返回OneController时就会修改OneController的控制器View的背景颜色,以及将TwoController界面UITextField里面输入的值传回第一个界面。
OneController的代码
#import "OneController.h"
#import "TwoController.h"
@interface OneController ()
@property (weak, nonatomic) IBOutlet UITextField *passWord;
@end
@implementation OneController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
TwoController *twoVc = [self.storyboard instantiateViewControllerWithIdentifier:@"TwoController"];
twoVc.myblock = ^(NSString *string,UIColor *color){
//括号里面的代码只有当TwoController点击事件触发,myBlock调用时,这段代码才会执行
self.view.backgroundColor = [UIColor blueColor];
self.passWord.text = string;//
};
[self presentViewController:twoVc animated:YES completion:^{
NSLog(@"LOG");
}];
}
TwoController的代码
#import "TwoController.h"
typedef void(^myBlock)(NSString *passWord, UIColor *bgColor);//
@interface TwoController ()
@property (nonatomic, copy) myBlock myblock;
@property (weak, nonatomic) IBOutlet UITextField *passWord;
@end
@implementation TwoController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UIColor *color = [UIColor redColor];
self.myblock(self.passWord.text,color);//调用block并传值
[self dismissViewControllerAnimated:YES completion:^{
NSLog(@"TWO");
}];
}
2、修改UIButton的点击事件
为什么要用block来重写按钮的点击事件?因为这样可以使代码简洁,点击事件直接放在block里面,不用在重新再定义一方法。
自定义UIButton点击事件
#import "XSButton.h"
@interface XSButton (){
buttonBlock _block;
}
@end
@implementation XSButton
- (void)hand:(buttonBlock)buttonAction{
_block = buttonAction;//赋值
[self addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
}
//点击事件
- (void)buttonAction{
if (_block) {//判断_block是否存在
_block();//调用代码块
}
}
控制器调用:
#import "ViewController.h"
#import "XSButton.h"
@interface ViewController ()
@property(nonatomic, strong)XSButton *button;
@end
@implementation ViewController
- (XSButton *)button{
if (!_button) {
_button = [XSButton buttonWithType:UIButtonTypeCustom];
[_button setTitle:@"按钮" forState:UIControlStateNormal];
_button.frame = CGRectMake(100,200,100, 100);
_button.backgroundColor = [UIColor redColor];
[_button hand:^{
NSLog(@"点击了----");//按钮点击事件
}];
}
return _button;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.button];
// Do any additional setup after loading the view, typically from a nib.
}
4、Block的内存管理(使用时引起的循环引用)
1、MRC:当Block内部使用局部对象时,局部对象的引用计数会加1; 当Block内部使用全局的对象时,全局对象的引用计数不会加1,但是持有全局对象的对象(当前对象self)引用计数会加1;
2、ARC:当block为当前对象的成员变量时(当前对象(self)持有block)
- block内部使用当前对象的实例变量时会造成循环引用
- block内部使用当前对象的实例方法也会造成循环引用
解决循环引用方法:使用__weak关键字修饰,weakSelf使用了弱引用,self也就使用了弱引用,block内部也就不会再持有当前对象(self)
__weak typeof(self)wekSelf = self;//ARC
__block typeof(self)wekSelf = self;//MRC
下面代码示例解决循环引用
#import "MyBlock.h"
typedef void(^myBlock)();//定义一个block别名
@interface MyBlock ()
@property (nonatomic, copy)myBlock block;//创建一个block变量
@property (nonatomic, strong)NSObject *obj;
@end
@implementation MyBlock
//循环引用,调用这个方法时,- (void)dealloc;不会调用
- (void)circularReference{
//当双方相互持有彼此时就会造成循环引用
self.block = ^{
NSLog(@"%@",self.obj);//当前d对象(self)持有self.block,这句代码又让self.block持有了当前对象(self)
[self method];//调用self的实例方法也会造成循环引用
};
}
//解决循环引用,调用这个方法时,- (void)dealloc;会调用
- (void)toooo{
__weak typeof(self)weakSelf = self;
self.block = ^{
NSLog(@"%@",weakSelf.obj);
[weakSelf method];
};
self.block();
//不会造成循环引用,myBlock为局部变量。
myBlock myBlock = ^{
NSLog(@"%@",self.obj);
};
myBlock();
}
- (void)dealloc{
NSLog(@"对象销毁了");
}
- (void)method{
}