浅谈block,类中带有Block参数的方法和Block的setting方法的先后顺序和区别
block创建后都在栈区存放的,block的语义特性必须用copy,通过copy可以将block从栈区放到堆区,保证每次使用block时block都存在,因此我们使用时常常要定义属性,使用属性是为了保存该block变量
首先在工程中创建BlockView(@interface BlockView : UIView)
在 BlockView .h中定义一个block变量和一个方法,方法的参数是block类型的
//第一步:定义一个ButtonActionBlock的block
typedef void(^ButtonActionBlock)(NSInteger tag);
@interface BlockView : UIView
//一个方法,方法的参数是block类型的
-(void)buttonActionBlock:(ButtonActionBlock)didClickButton;
@end
在BlockView.m中
#import "BlockView.h"
@interface BlockView()
//Block
//block创建后都在栈区存放的,block的语义特性必须用copy,通过copy可以将block从栈区放到堆区,保证每次使用block时block都存在
//声明一个block
@property(nonatomic,copy)ButtonActionBlock buttonActionBlock;
@property(nonatomic,strong)UIButton *button;
@end
@implementation BlockView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CGFloat x = 5;
CGFloat y = 5;
CGFloat width = 65;
CGFloat height = 40;
//创建button
for (int i = 0; i < 4; i ++) {
self.button = [UIButton buttonWithType:(UIButtonTypeSystem)];
self.button.frame = CGRectMake(x + i * (width + 10), y, width, height);
self.button.tag = 100 + i;
self.button.backgroundColor = [UIColor cyanColor];
self.button.layer.cornerRadius = 5;
self.button.layer.masksToBounds = YES;
[self.button setTitle:[NSString stringWithFormat:@"%d",i] forState:UIControlStateNormal];
[self.button addTarget:self action:@selector(handleButton:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_button];
}
}
return self;
}
//处理button的点击事件,将tag值传给block的参数 回调block
-(void)handleButton:(UIButton *)button
{
NSLog(@"3");
NSInteger tag = button.tag;
//第二步,回掉block
self.buttonActionBlock(tag),
NSLog(@"6");
NSLog(@"7");
}
//该方法中self.buttonActionBlock = didClickButton;执行后会调用属性buttonActionBlock的setter方法,将block变量didClickButton传给setter方法的参数
-(void)buttonActionBlock:(ButtonActionBlock)didClickButton
{
NSLog(@"1");
NSLog(@"-----------didClickButton = %p",didClickButton);
self.buttonActionBlock = didClickButton;
}
//重写属性buttonActionBlock的setter方法,在此重写setter方法目的是为了表明该方法是把传进来的block变量进行深拷贝,拷贝到了堆区,并赋给了实例变量_buttonActionBlock,使我们在任何时候都能使用block变量(block的创建后在栈区,出了方法就被回收,无法再使用)
- (void)setButtonActionBlock:(ButtonActionBlock)buttonActionBlock
{
NSLog(@"2");
if (_buttonActionBlock != buttonActionBlock) {
NSLog(@"++++++++buttonActionBlock = %p",buttonActionBlock);
_buttonActionBlock = [buttonActionBlock copy];
}
}
@end
ViewController .m文件中导入BlockView.h文件
ViewController .m文件 中代码实现
#import "ViewController.h"#import "BlockView.h"// 获取RGB颜色#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]#define LOADIMAGE(a) [UIImage imageNamed:[NSString stringWithFormat:@"2_%d.jpg",a]];@interface ViewController ()@property (nonatomic, strong) UIImageView *YJFImageView;
@interface ViewController ()@property (nonatomic, strong) UIImageView *YJFImageView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = RGBA(252, 230, 201, 1.0);
BlockView *blockView = [[BlockView alloc] initWithFrame:CGRectMake(10, 0, 320 - 20, 50)];
blockView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:blockView];
//BlockView的对象blockView调用其方法buttonActionBlock:
//第三步,调用block
[blockView buttonActionBlock:^(NSInteger tag) {
//block的实现
NSLog(@"4");
[self handleButton:tag];
NSLog(@"5");
}];
[self createView];
}
//处理自定义toolBar的点击事件
-(void)handleButton:(NSInteger)tag
{
switch (tag) {
//...按钮
case 100:
{
self.YJFImageView.image = LOADIMAGE(2);
}
break;
//...按钮
case 101:
{
self.YJFImageView.image = LOADIMAGE(5);
}
break;
//...按钮
case 102:
{
self.YJFImageView.image = LOADIMAGE(6);
}
break;
//...按钮
case 103:
{
self.YJFImageView.image = LOADIMAGE(4);
}
break;
default:
break;
}
}
-(void)createView
{
self.YJFImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 52, 320 - 20, 568 - 64 - 75)];
self.YJFImageView.image = LOADIMAGE(8);
self.YJFImageView.userInteractionEnabled = YES;
[self.view addSubview:_YJFImageView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
通过程序运行控制台输出结果如下:
点击button前:
由此结合代码实现中打的log可以看出:didClickButton和传入属性的setter方法的参数是一个地址,则buttonActionBlock:方法中把didClickButton拷贝了一份到堆区,并赋值给实例变量_buttonActionBlock
结合代码实现中打的log可以看出整个Block的执行过程,也可以通过打断的查看Block的执行过程
http://www.tuicool.com/articles/AvURva学习链接