标签: iOS 技术
接上篇,继续block研究,这一篇讲解实战中的block反向传值,一个非常实用的技术。
block反向传值
- 前面我们已经得知,block可以作为参数而进行传递
- 也知道block是封装了一段代码块,如同函数一样,我们可以调用它,并用来传递一些信息,比如某个我们需要的参数值!
- 但block的经典使用,还是其反向传值的简单明了
先看代码
#import "TCHomeViewController.h"
#import "TCHomeCell.h"
static NSString *const kTCHomeCellIdentifier = @"TCHomeCell";
@interface TCHomeViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray<NSString *> *titles;
@end
@implementation TCHomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.titles = @[].mutableCopy;
[self setupUI];
[self setupData];
}
#pragma mark - UI
- (void)setupUI {
[self.view addSubview:self.tableView];
self.tableView.frame = self.view.bounds;
[self.tableView registerClass:[TCHomeCell class] forCellReuseIdentifier:kTCHomeCellIdentifier];
}
- (void)setupData {
NSArray *arr = @[@"我是谁!",
@"我是人!🙄",
@"我是诗人!🙄",
@"我是大诗人!🙄",
@"我是伟大诗人!🙄"];
self.titles = [NSMutableArray arrayWithArray:arr];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.titles.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TCHomeCell *cell = [tableView dequeueReusableCellWithIdentifier:kTCHomeCellIdentifier forIndexPath:indexPath];
cell.title = self.titles[indexPath.row];
cell.homeCellBtnClickBlock = ^(BOOL isSelected) {
// 拿到isSelected值,作进一步操作
if (isSelected) {
NSLog(@"下载中");
}
};
return cell;
}
#pragma mark - getter
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] init];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.rowHeight = 60.0f;
}
return _tableView;
}
@end
#import <UIKit/UIKit.h>
typedef void(^TCHomeCellBtnClickBlock)(BOOL isSeleted);
@interface TCHomeCell : UITableViewCell
@property (nonatomic, copy) TCHomeCellBtnClickBlock homeCellBtnClickBlock;
@property (nonatomic, strong) NSString *title;
@end
#import "TCHomeCell.h"
@interface TCHomeCell ()
/// 标题标签
@property (nonatomic, strong) UILabel *titleLabel;
/// 下载按钮
@property (nonatomic, strong) UIButton *downloadBtn;
@end
@implementation TCHomeCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self setupUI];
}
return self;
}
#pragma mark - UI
- (void)setupUI {
[self.contentView addSubview:self.titleLabel];
[self.contentView addSubview:self.downloadBtn];
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
self.titleLabel.frame = CGRectMake(10, 10, width * 0.5, height * 0.8);
self.downloadBtn.frame = CGRectMake(width, 10, 80, height * 0.8);
}
#pragma mark - action
- (void)clickDownloadBtn:(UIButton *)btn {
BOOL selected = !btn.selected;
if (self.homeCellBtnClickBlock) {
self.homeCellBtnClickBlock(selected);
}
}
#pragma mark - setter
- (void)setTitle:(NSString *)title {
if ([_title isEqualToString:title]) {
return;
}
_title = title;
self.titleLabel.text = _title;
}
#pragma mark - getter
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.font = [UIFont systemFontOfSize:17.0];
_titleLabel.textColor = [UIColor blackColor];
[_titleLabel sizeToFit];
}
return _titleLabel;
}
- (UIButton *)downloadBtn {
if (!_downloadBtn) {
_downloadBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_downloadBtn.frame = CGRectMake(0, 0, 100, 40);
_downloadBtn.backgroundColor = [UIColor darkGrayColor];
[_downloadBtn setTitle:@"download" forState:UIControlStateNormal];
[_downloadBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];
[_downloadBtn addTarget:self action:@selector(clickDownloadBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _downloadBtn;
}
@end
说明
- 第一段代码是控制器里面的代码,处理业务逻辑
- 第二段代码是视图cell的.h代码,提供了两个API
- 第三段代码是视图cell的.m代码,是处理视图和数据展示的
解释
- 在cell的.h文件中,定义了一个block属性,并定义了一个形参
BOOL isSelected
,那么这个形参就是我们需要传递的值,即传给控制器的进行业务处理的值- 在.m文件中,通过按钮的点击事件
-clickDownloadBtn:
来进行block回调,即self.homeCellBtnClickBlock(selected);
- 那么我们需要用这个block来传值,即
selected
,利用这个BOOL值来做进一步操作,每一个cell都是不同的,而且我们也只能通过cell对象来访问block属性,故而block块写在了cell的初始化中,当我们点击cell的按钮,就会有相应的操作,在代码中的block块是NSLog代码
,通过这些打印我们知道按钮的变化,而这些逻辑就恰好交由控制器处理,正好也体现了MVC的设计思想
程序运行展示
点击事件
点击download
按钮,就会在控制台上看到打印输出
2016-12-06 11:11:08.177 TCMyBlockDemo[8816:2632787] -[ViewController clickBtn:]
2016-12-06 11:11:16.283 TCMyBlockDemo[8816:2632787] 下载中
由此说明,传值成功!
写在最后
反向传值是block最实用的技术,当然也可以用代理来传值,但定义代理、实现代理,是一个比较繁复的过程,而且代码也不精简。
对代理熟悉的朋友可以试试,相信这样的实战在项目中经常用到,如果你用腻了代理,那么不妨试试block
那么,关于block实战的大致内容也就差不多结束了,至于block在堆栈是怎么存在的,有很多文章可以搜到。我个人的block系列文章,都是在实战中用到的,相信可以为一部分迷茫的朋友有所帮助,当然如果真帮到了你,那么我这辛苦也就值了。
最后,感谢点赞,欢迎批评指正,欢迎转载,完结!