前段时间,一个偶然的机会,让我遇到了
BlocksKit
和RAC(ReactiveCocoa)
,说来惭愧,做iOS开发这么久,到目前为止还有很多东西不熟悉,偶然遇到一个“新词”完全一脸懵逼,根本就不知道是啥玩意。所以现在有时间就会到处逛,看到一个就会记录一个,当前时间看不完的,我会记录起来,找时间慢慢的看。在此还要问一下大家学习iOS相关知识的都有哪些好的网站或好的去处,麻烦评论留下,谢过了……
说到
BlocksKit
和RAC
,之前网上查了一下。我是先看的RAC
,因为第一眼我看成了ARC,我说这东西不是自动管理内存的吗,后面再仔细看,原来是RAC
,是ReactiveCocoa
的缩写。目前我查到的资料都说RAC
配合MVVM框架使用,体验感超级棒,简单看了下,说了很多什么信号之类的东西,因为在我开发的过程中,也从来没用过这个RAC
,所以一时半会看的我头昏眼花,然后就暂时放着不看了。转眼看看BlocksKit
,看到最后我发现这两东西好像就是一回事似的,因为都是各种Block,搞的现在看啥东西都觉得像是需要加上一对{}才行。
还有一个奇怪的现象,文章看完的时候我是习惯性要看一下各位的评论的,因为评论里面的内容往往会很精彩,有时候会发现一些对我来说比较新的东西,这个时候我就发现很多类似的说法,总结一下就是无论是
BlocksKit
还是RAC
,都会和很多库产生冲突,早以放弃使用这两个框架。因为我没在项目里面用过BlocksKit
和RAC
,朋友们又没具体说会和哪些库产生冲突,所以我更不清楚到底是怎么回事了。当然了,看过的文章大部分都是15、16、17年的,有一些是18年的,特意筛选了近一年内关于BlocksKit
和RAC
的文章,很明显文章数少了很多,难道真的早就没人在用了吗?
不管怎么说,既然被我看到了,至少我也得看看源码吧。首先着手看的是
BlocksKit
,还看了一些以前的文章,大致了解了它的用法,接下来,我会简单的说一下我对BlocksKit
的理解和简单的使用。
BlocksKit理解
看源码可以看出各种Block,对我们经常用的一些控件做了很多的扩展,也算是对一些常用的方法封装了一层,调用的时候代码量减少了很多,直观感觉清晰了很多。还有对一些不具备某些特性功能的控件增加了方法,比如说UIView添加点击事件等等。
- 接下来对
BlocksKit
做一些简单的代码test,大神勿喷!
首先添加
BlocksKit
到你的TestProject,我是用CocoaPods来管理这些第三方框架的,不会使用CocoaPods的看这里
然后引入你用到的这个框架的头文件,我用到了三个,分别如下:
#import <BlocksKit/BlocksKit.h>
#import <BlocksKit/A2DynamicDelegate.h>
#import <BlocksKit/BlocksKit+UIKit.h>
UIView
UIView是我们经常用到的一个控件,
UIView
继承UIResponder
,UIResponder
继承NSObject
,这些大家查看API就知道了,我在这有点废话了。后面的一些控件也不再废话了,直接看test代码。
- 给UIView添加点击事件,首先初始化控件,添加到self.view上。类似的简单代码不再重复。
UIView *vBlock = [UIView new];
vBlock.backgroundColor = [UIColor orangeColor];
[self.view addSubview:vBlock];
[vBlock mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(200, 200));
make.centerX.mas_equalTo(self.view.mas_centerX);
make.centerY.mas_equalTo(self.view.mas_centerY);
}];
- 调用方法为
- (void)bk_whenTapped:(void (^)(void))block;
文档解释是这样说的,后面的文档说明代码不再粘贴,大家可以自行下载源码查看,源码下载地址
/** Adds a recognizer for one finger tapping once.
@warning This method has an _additive_ effect. Do not call it multiple
times to set-up or tear-down. The view will discard the gesture recognizer
on release.
@param block The handler for the tap recognizer
@see whenDoubleTapped:
@see whenTouches:tapped:handler:
*/
- 调用
/*
给View添加点击事件
*/
[vBlock bk_whenTapped:^{
NSLog(@"view点击");
}];
说明:我只是随便选了几个控件,并从每个控件的扩展方法里选了几个简单的方法试了试,没有对全部代码进行解读,大家有兴趣的可以自己去玩一玩。
UIButton
给Button添加事件的常规写法是先添加方法,然后再实现这个方法,代码如下:
/*
给Button添加事件
*/
[btnBlock addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
/*
实现方法
*/
-(void)buttonAction{
NSLog(@"buttonAction");
}
如果要传参数的话,代码如下:
/*
给Button添加事件
*/
[btnBlock addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
/*
实现方法
*/
-(void)buttonAction:(UIButton *)sender{
NSLog(@"buttonAction = %ld",sender.tag);
}
BlocksKit
就为我们提供了这么一个精简的代码段,如下:
[btnBlock bk_addEventHandler:^(id sender) {
NSLog(@"按钮点击");
} forControlEvents:UIControlEventTouchUpInside];
如果同样是需要传参数的呢?注意,这里需要自己手动把
(id sender)
改写成(UIButton *sender)
代码如下:
[btnBlock bk_addEventHandler:^(UIButton *sender) {
NSLog(@"按钮点击 = %ld",sender.tag);
} forControlEvents:UIControlEventTouchUpInside];
NSDictionary
- 先初始化一个NSDictionary测试用
NSDictionary *dict = @{@"name":@"xiaohong",
@"age":@"18",
@"sex":@"女"};
遍历字典,查找字典中是否存在某些Key,并同时返回一个新的字典
调用方法为- (NSDictionary *)bk_select:(BOOL (^)(id key, id obj))block;
NSDictionary *dictEnd1 = [dict bk_select:^BOOL(id key, id obj) {
NSLog(@"key = %@ obj = %@",key,obj);
if ([key isEqualToString:@"name"] || [key isEqualToString:@"age"]) {
return YES;
}else{
return NO;
}
}];
NSLog(@"dictEnd1 = %@",dictEnd1);
打印结果
bk_select.png
- 从打印结果看到,字典被整个遍历了一遍,把符合条件里的
name
和age
两组键值对装到了一个新的字典里返回
根据以往的经验想一下,既然能把符合条件的键值对返回给我们,那肯定也能把不符合条件的键值对返回给我们吧?答案是肯定的,这样的方法同样也存在一个,它就是
- (NSDictionary *)bk_reject:(BOOL (^)(id key, id obj))block;
NSDictionary *dictEnd2 = [dict bk_reject:^BOOL(id key, id obj) {
NSLog(@"key = %@ obj = %@",key,obj);
if ([key isEqualToString:@"name"] || [key isEqualToString:@"age"]) {
return YES;
}else{
return NO;
}
}];
NSLog(@"dictEnd2 = %@",dictEnd2);
打印结果
bk_reject.png
- 从打印结果看到,字典被整个遍历了一遍,把不符合条件里的
sex
一组键值对装到了一个新的字典里返回
遍历字典,修改字典里每个Key对应的Value值,并同时返回一个新的字典,调用方法为
- (NSDictionary *)bk_map:(id (^)(id key, id obj))block;
NSDictionary *dictEnd3 = [dict bk_map:^id(id key, id obj) {
NSLog(@"key = %@ obj = %@",key,obj);
return [NSString stringWithFormat:@"%@-edited",obj];
}];
NSLog(@"dictEnd3 = %@",dictEnd3);
打印结果
bk_map.png
NSArray
- 先初始化一个NSArray测试用
NSArray *stringArray = @[@"img5",@"img1",@"img2",@"img3",@"img4"];
遍历数组,调用方法为
- (void)bk_each:(void (^)(id obj))block;
[stringArray bk_each:^(id obj) {
NSLog(@"obj = %@",obj);
}];
- 遍历数组呢,系统本身有提供方法,我们自己也可以for循环处理,但是很显然
BlocksKit
提供的这个方法代码量很精简,用起来也比较直观。
遍历数组,查找目标元素,并返回,调用方法为
- (id)bk_match:(BOOL (^)(id obj))block;
id some = [stringArray bk_match:^BOOL(id obj) {
NSLog(@"obj = %@",obj);
if ([obj isEqualToString:@"img3"]) {
return YES;
}
return NO;
}];
NSLog(@"some = %@",some);
打印结果
bk_match.png
UITableView
通过看源码发现一个有趣的事,在
A2DynamicDelegate.h
里有这么一段说明,如下:
// Create an alert view
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Hello World!"
message:@"This alert's delegate is implemented using blocks. That's so cool!"
delegate:nil
cancelButtonTitle:@"Meh."
otherButtonTitles:@"Woo!", nil];
// Get the dynamic delegate
A2DynamicDelegate *dd = alertView.bk_dynamicDelegate;
// Implement -alertViewShouldEnableFirstOtherButton:
[dd implementMethod:@selector(alertViewShouldEnableFirstOtherButton:) withBlock:^(UIAlertView *alertView) {
NSLog(@"Message: %@", alertView.message);
return YES;
}];
// Implement -alertView:willDismissWithButtonIndex:
[dd implementMethod:@selector(alertView:willDismissWithButtonIndex:) withBlock:^(UIAlertView *alertView, NSInteger buttonIndex) {
NSLog(@"You pushed button #%d (%@)", buttonIndex, [alertView buttonTitleAtIndex:buttonIndex]);
}];
// Set the delegate
alertView.delegate = dd;
[alertView show];
对这段代码的解释是这样的:
A2DynamicDelegate implements a class's delegate, data source, or other delegated protocol by associating protocol methods with a block implementation.
翻译的大概意思就是:A2DynamicDelegate可以用Block的形式去实现类的委托、数据源或其他委托协议。
那么仿照这段代码,可以试试UITableView,因为UITableView既有DataSource,也有Delegate。首先,我用懒加载的方式创建TableView,用Masonry创建布局(这部分代码忽略),先把代码贴出来看下,代码如下:
-(UITableView *)tableView{
if (!_tableView) {
//初始化TableView
_tableView = [[UITableView alloc]init];
#pragma mark - 设置Source
//先把TableView的Source和BlockKit绑定
A2DynamicDelegate *dataSource = _tableView.bk_dynamicDataSource;
[dataSource implementMethod:@selector(tableView:numberOfRowsInSection:) withBlock:^NSInteger(UITableView *tableView, NSInteger section){
return 10;
}];
[dataSource implementMethod:@selector(tableView:cellForRowAtIndexPath:) withBlock:^UITableViewCell *(UITableView *tableView, NSIndexPath *indexPath){
static NSString *ident = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ident];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ident];
}
cell.backgroundColor = [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1];
return cell;
}];
_tableView.dataSource = (id)dataSource;//必须有这句,把dataSource传回给TableView
#pragma mark - 设置Delegate
//先把TableView的Delegate和BlockKit绑定
A2DynamicDelegate *delegate = _tableView.bk_dynamicDelegate;
[delegate implementMethod:@selector(tableView:heightForRowAtIndexPath:) withBlock:^CGFloat(UITableView *tableView, NSIndexPath *indexPath){
return 80.f;
}];
[delegate implementMethod:@selector(tableView:didSelectRowAtIndexPath:) withBlock:^(UITableView *tableView, NSIndexPath *indexPath){
NSLog(@"indexPath = %ld",indexPath.row);
}];
_tableView.delegate = (id)delegate;//必须有这句,把delegate传回给TableView
}
return _tableView;
}
-
这段代码就把一个TableView创建好了,调用一次
[self.view addSubview:self.tableView];
就把TableView添加到View上去了,是不是很神奇。
比以往的那种要先写<UITableViewDelegate,UITableViewDataSource>
,然后再添加代理,添加代理就类似上面代码里面的A2DynamicDelegate *dataSource = _tableView.bk_dynamicDataSource;
,不过上面的代码在实现了方法之后,还要调用_tableView.dataSource = (id)dataSource;
,这一步就相当于传统写法里面的添加代理那一步了。 -
到这里用
BlocksKit
创建TableView就创建完了,怎么说呢,以前我也没这样写过,这是唯一一次这样写,这种写法也许会有很多人喜欢,能被很多人接受,其实只要仔细看一看……这个要怎么说呢?我想不到什么形容词,最后的感想就是,我可能不会这样写……
好了,到此为止,就是我对
BlocksKit
所认识的一部分,写的不好,大神勿喷。至于这个框架会不会在以后的项目中使用,那还得看情况了……
网友评论