美文网首页
iOS BlocksKit初体验

iOS BlocksKit初体验

作者: 邓布利多教授 | 来源:发表于2019-08-11 14:09 被阅读0次

    前段时间,一个偶然的机会,让我遇到了BlocksKitRAC(ReactiveCocoa),说来惭愧,做iOS开发这么久,到目前为止还有很多东西不熟悉,偶然遇到一个“新词”完全一脸懵逼,根本就不知道是啥玩意。所以现在有时间就会到处逛,看到一个就会记录一个,当前时间看不完的,我会记录起来,找时间慢慢的看。在此还要问一下大家学习iOS相关知识的都有哪些好的网站或好的去处,麻烦评论留下,谢过了……

    说到BlocksKitRAC,之前网上查了一下。我是先看的RAC,因为第一眼我看成了ARC,我说这东西不是自动管理内存的吗,后面再仔细看,原来是RAC,是ReactiveCocoa的缩写。目前我查到的资料都说RAC配合MVVM框架使用,体验感超级棒,简单看了下,说了很多什么信号之类的东西,因为在我开发的过程中,也从来没用过这个RAC,所以一时半会看的我头昏眼花,然后就暂时放着不看了。转眼看看BlocksKit,看到最后我发现这两东西好像就是一回事似的,因为都是各种Block,搞的现在看啥东西都觉得像是需要加上一对{}才行。

    还有一个奇怪的现象,文章看完的时候我是习惯性要看一下各位的评论的,因为评论里面的内容往往会很精彩,有时候会发现一些对我来说比较的东西,这个时候我就发现很多类似的说法,总结一下就是无论是BlocksKit还是RAC,都会和很多库产生冲突,早以放弃使用这两个框架。因为我没在项目里面用过BlocksKitRAC,朋友们又没具体说会和哪些库产生冲突,所以我更不清楚到底是怎么回事了。当然了,看过的文章大部分都是15、16、17年的,有一些是18年的,特意筛选了近一年内关于BlocksKitRAC的文章,很明显文章数少了很多,难道真的早就没人在用了吗?

    不管怎么说,既然被我看到了,至少我也得看看源码吧。首先着手看的是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继承UIResponderUIResponder继承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
    • 从打印结果看到,字典被整个遍历了一遍,把符合条件里的nameage两组键值对装到了一个新的字典里返回

    根据以往的经验想一下,既然能把符合条件的键值对返回给我们,那肯定也能把不符合条件的键值对返回给我们吧?答案是肯定的,这样的方法同样也存在一个,它就是- (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提供的这个方法代码量很精简,用起来也比较直观。
    打印结果 bk_each.png

    遍历数组,查找目标元素,并返回,调用方法为- (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所认识的一部分,写的不好,大神勿喷。至于这个框架会不会在以后的项目中使用,那还得看情况了……

    全剧终

    相关文章

      网友评论

          本文标题:iOS BlocksKit初体验

          本文链接:https://www.haomeiwen.com/subject/jasrjctx.html