首页 > 代码库 > 教你爱上Block(闭包)

教你爱上Block(闭包)

block定义

// 定义
返回类型 (^block名字)(参数类型) = ^(参数){

    代码

}

简单用法

定义了Block代码块之后,就可以将一整块代码当做一个变量来使用,变量可为局部变量,也可为全局变量,这也是我认为Block最方便之处。

假设要生成两个数组,一个装有5个随机数,一个装有10个随机数,将生成随机数的方法定义为一个闭包,在后文既可直接访问,如

NSNumber *(^randArray)(void) = ^{
      int rand = arc4random() % 100;

      NSNumber *number = [NSNumber numberWithInt:rand];
      return number;
  };

  NSMutableArray *array1 = [[NSMutableArray alloc] init];
  NSMutableArray *array2 = [[NSMutableArray alloc] init];

  for (NSInteger index = 0; index<10; index++) {
      [array1 addObject:randArray];
  }

  for (NSInteger index = 0; index<5; index++) {
      [array2 addObject:randArray];
  }

回调

下面给出一 tableViewCell 上按钮事件回调的例子,这个也是很多人头痛的问题,通过block可以很方便地实现,而且层次非常清晰。

自定义cell命名为blockCell,cell上放一 switch 控件,我们希望switch被点击时在viewController中可以得到switch的状态,获取到点击事件。

blockCell.h 中定义一Block

typedef void(^switchAction)(blockCell *);
@property (nonatomic,copy)switchAction action;

在switch的点击时间事件中调用switchAction

blockCell.m

- (IBAction)switchToggle:(id)sender {
    self.action(self);
}

viewController 中使用这个自定义Cell对table进行初始化

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    NSString *cellID = @"blockCell";

    blockCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    cell.action = ^(blockCell *cell){
        // 既可取到行,也可取到switch状态
        NSLog(@"行数:%ld, switch state: %u", (long)indexPath.row, cell.switchBtn.on);

    };

    return cell;
}

Block封装

现在很多流行地第三方库都将回调改成了Block,之前用的Delegate特别得心应手有木有,都封装好了直接调用得到我要的结果,好了,都改成Block,不知道如何去接Block的返回值,只能一遍又一般地重写。

其实要封装很容易,将第三方库返回的Block,以一个Block来接住再返回调用的页面就可以了,本想介绍
AFNetworing后再讲这个,但是我看了下,github上他们的主页的readMe写得超级清楚详细,想要了解的童鞋请仔细看下他们的readMe

添加方式

Github地址:https://github.com/AFNetworking/AFNetworking

可以将类库拷贝到工程目录下添加,推荐用 cocoapods 安装,方便更新,而且不用手动导入framework,一键设置

封装

目的:将参数传递后调用对应的方法直接得到网络返回值

新建一个类WebRequest ,此处写一个示例,大家自己参考

#import <Foundation/Foundation.h>

#import "AFNetworking.h"

@interface WebRequest : NSObject


-(void)requestNameWithID:(NSString *)ID WithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject, NSDictionary *myData))success
                 failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;

@end





@implementation WebRequest

-(void)requestNameWithID:(NSString *)ID WithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject, NSDictionary *myData))success
                 failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{


    NSURL *url = [NSURL URLWithString:@"用ID拼接地接口地址"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        NSDictionary *dic = responseObject[@"someKey"];

        success(operation, responseObject, dic);// 此处将网络返回值传递给我们自己定义的Block中的三个返回值,dic可以自定义,也可不加,如此可以返回经自己在这里已经处理好的对象,而不必调用一次,处理一次

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        failure(operation,error);// 与方法定义中的Block一致
    }];

}


@end

调用

WebRequest *request = [[WebRequest alloc] init];

[request requestNameWithID:@"123" WithSuccess:^(AFHTTPRequestOperation *operation, id responseObject, NSDictionary *myData) {

    // 在网络成功时在这里就可以得到返回值了

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

    // 网络失败回调

}];


示例工程下载


芳仔说:

现在越来越多地库使用Block,^作为Block的标志,初看会很不适应,而且在未使用的情况下会对其有抵触心理

iOS8也有相当多的Block操作,Block出现已经有两年多了,正如日中天,取代delegate 也不远了,相信大家再稍微探究使用后会爱上它的,祝大家好运!

我建的QQ交流群:130283564,欢迎半年以上经验iOS开发者加入,加群请写一句OC验证,或注明开源中国

教你爱上Block(闭包)