Block

作者: 苹果上的小豌豆 | 来源:发表于2016-09-10 11:28 被阅读0次

    Block究竟有哪些称呼和官方的解释。

    匿名函数,块函数,块,block基本上他们都是同一个鸟人。

    维基百科中说,Block是Apple Inc.为C,C++,以及OC 添加的新特性,使得它们可以用lambda表达式的语法来创建闭包.(lambda表达式既匿名函数表达式,闭包既是可以包含自由(未绑定到特定对象)变量的代码块,具体可以自己下去认真理解下)。我理解为block就是用匿名函数表达式创建的代码块.

    闭包就是能够读取其它函数内部变量的函数

    什么时候使用block.

    Block除了能够定义参数列表、返回类型外,还能够获取被定义时的词法范围内的状态(比如局部变量),并且在一定条件下(比如使用__block变量)能够修改这些状态。此外,这些可修改的状态在相同词法范围内的多个block之间是共享的,即便出了该词法范围(比如栈展开,出了作用域),仍可以继续共享或者修改这些状态。通常来说,block都是一些简短代码片段的封装,适用作工作单元,通常用来做并发任务、遍历、以及回调。

    block如何声明

    [转载]iOS中block实际应用初探

    int (*CFunc)(int a) 函数调用 int result = CFunc(10);

    int (^BFunc)(int a) 函数调用 int result = BFunc(10);

    block用法1

    void (^myblocks) (void) = NULL;

    myblocks = ^(void) {

    NSLog(@"in blocks");

    };

    NSLog(@"before myblocks");

    myblocks();

    NSLog(@"after myblocks");

    int (^myblocks2) (int a, int b) = ^(int a, int b) {

    int c = a + b;

    return c;

    };

    NSLog(@"before blocks2");

    int ret = myblocks2(10, 20);

    NSLog(@"after blocks2 ret %d", ret);

    //此处如果不加__block会报错

    __block int sum = 0;

    int (^myblocks3) (int a, int b) = ^(int a, int b) {

    sum = a + b;

    return 3;

    };

    myblocks3(20, 30);

    NSLog(@"sum is %d", sum);

    对于这种用法,本人不才,基本没有在实际项目中用过.因为我的理解这实际意义不大(如果是这种简单的计算),唯一作用是提高程序的并发性.

    回调是block一个重要的特性.

    block回调是我在网络请求中用得最多的.

    这里先用前辈在ASIHTTP中的block为例子.

    定义block

    #if NS_BLOCKS_AVAILABLE

    typedef void (^ASIBasicBlock)(void);

    typedef void (^ASIHeadersBlock)(NSDictionary *responseHeaders);

    typedef void (^ASISizeBlock)(long long size);

    typedef void (^ASIProgressBlock)(unsigned long long size, unsigned long long total);

    typedef void (^ASIDataBlock)(NSData *data);

    #endif

    此定义可以是全局的block,

    这里只用了上门定义的其中一个block为例,作为ASIHTTPRequest的一个属性.(意思是block可以作为一个对象的属性存在)

    @interface ASIHTTPRequest : NSOperation {

    ASIBasicBlock completionBlock;

    }

    //向外暴露一个接口  这里是为回调留一接口方法,其实也可以不用留

    - (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock;

    方法实现(这里用release是为开启arc)

    @implementation ASIHTTPRequest

    - (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock

    {

    [completionBlock release];

    completionBlock = [aCompletionBlock copy];

    }

    这里是网络请求完成后的方法,在这里实现我们block的调用.

    - (void)reportFinished

    {

    #if NS_BLOCKS_AVAILABLE

    if(completionBlock){

    completionBlock();

    }

    #endif

    }

    @end

    如下,然后你可以在你请求网络的类实现中,实现网络请求并获取网络请求成功后的回调, 这里可以回传参数变量(我们这个例子block是回传的参数为void,--typedef void (^ASIBasicBlock)(void)--).在这里回传参数就是,上面说的参数共享,就象遍历数组,这样也许你更能理解

    [arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

    }];

    这里的obj 和idx 以及stop都可以为你在回调时候所用,就好比代理delegate回传参数一样.

    ASIHTTPRequest *request = [self requestWithUrl:url];

    //请求成功

    [request setCompletionBlock:^{

    switch (request.responseStatusCode) {

    case RequestStatus_OK:

    complete(request.responseString);break;

    case RequestStatus_ErrorRequest:

    failed(@"错误的请求");break;

    case RequestStatus_NotFound:

    failed(@"找不到指定的资源");break;

    case RequestStatus_Error:

    failed(@"内部服务器错误");break;

    default:

    failed(@"服务器出错");break;

    }

    }];

    //请求失败

    [request setFailedBlock:^{

    failed(@"网络连接失败");

    }];

    这里的FailedBlock我们没有举例实现.



    看了前辈的block实现,兄弟伙写是否有所理解?接下来看看,我写的一个block的简单用法.

    第一种,接网络请求的block自己再次封装的方法.把block作为方法参数使用.

    @interface JHttpRequest : NSObject

    //异步Get请求

    + (ASIHTTPRequest *)asyncGetRequest:(NSString *)url complete:(void (^)(NSString *responseStr))complete failed:(void (^)(NSString *errorMsg))failed;

    //异步Get请求带缓存

    //异步Post请求

    //异步Post上传图片

    //异步下载请求

    //生成异步请求对象

    @end

    //发送异步Get请求

    + (ASIHTTPRequest *)asyncGetRequest:(NSString *)url

    complete:(void (^)(NSString *responseStr))complete

    failed:(void (^)(NSString *errorMsg))failed{

    ASIHTTPRequest *request = [self requestWithUrl:url];

    [request setUserAgent:UserAgent];

    [request setTimeOutSeconds:5.];

    //请求成功

    [request setCompletionBlock:^{

    switch (request.responseStatusCode) {

    case RequestStatus_OK:

    complete(request.responseString);break;

    case RequestStatus_ErrorRequest:

    failed(@"错误的请求");break;

    case RequestStatus_NotFound:

    failed(@"找不到指定的资源");break;

    case RequestStatus_Error:

    failed(@"内部服务器错误");break;

    default:

    failed(@"服务器出错");break;

    }

    }];

    //请求失败

    [request setFailedBlock:^{

    failed(@"网络连接失败");

    }];

    //开始请求

    [request startAsynchronous];

    return request;

    }

    下面是你需要调用网络接口的viewcontroller种对上面网络请求block方法的调用

    [JHttpRequest asyncGetRequest:url complete:^(NSString *responseStr) {

    if (responseStr) {

    NSDictionary *getDic = [responseStr JSONValue];

    if ([[getDic objectForKey:@"success"] boolValue]) {

    //getDic 请求成功取得的json数据

    }else{

    faild([getDic objectForKey:@"msg"]);

    }

    }else{

    faild(@"获取信息失败");

    }

    } failed:^(NSString *errorMsg) {

    faild(errorMsg);

    }];

    综上例子所诉,block可以作为一个方法参数使用,能更方便地去取得回调数据.

    第二种,把block作为类的属性来使用.

    //定义一个block作为viewcontroler的一个属性.

    @interface FirstViewController : UIViewController{

    //定义一个blocks变量

    void (^BarkCallback) (FirstViewController *thisDog, int count);

    NSInteger barkCount;

    }

    @property(nonatomic , copy) void (^BarkCallback) (FirstViewController *thisDog, int count);

    @end

    其中void (^BarkCallback) (FirstViewController *thisDog, int count);thisDog count是参数.

    @implementation FirstViewController

    @synthesize BarkCallback;

    - (void)viewDidLoad

    {

    [super viewDidLoad];

    barkCount = 0;

    //这里我们启动一个定时器方便回调看效果

    [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];

    }

    -(void) updateTimer:(id) arg

    {

    barkCount ++;

    if (BarkCallback) {

    //调用从其他类传过来的BarkCallback

    BarkCallback(self, barkCount);

    }

    }

    @end

    实现block

    FirstViewController *viewController = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];

    viewController.BarkCallback = ^(FirstViewController *thisDog, int count) {

    NSLog(@"count == %d", count);

    };

    把block作为类的属性来使用.还有一种表达方法.

    typedef void (^BarkCallback) (FirstViewController *thisDog, int count);

    @interface FirstViewController : UIViewController{

    NSInteger barkCount;

    }

    @property (nonatomic, copy) BarkCallback completionHandler;

    @end

    @implementation FirstViewController

    @synthesize completionHandler;

    - (void)viewDidLoad

    {

    [super viewDidLoad];

    barkCount = 0;

    [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];

    }

    -(void) updateTimer:(id) arg

    {

    barkCount ++;

    if (completionHandler) {

    completionHandler(self, barkCount);

    }

    }

    @end

    实现block

    FirstViewController *viewController = [[FirstViewController alloc]initWithNibName:@"FirstViewController" bundle:nil];

    BarkCallback myab = ^(FirstViewController *thisDog, int count) {

    NSLog(@"count == %d", count);

    };

    viewController.completionHandler = myab;

    把block作为全局变量来使用.(无意间奇葩地自己创造出来的)

    void (^ BarkCallback) (FirstViewController *thisDog, int count);

    @interface FirstViewController : UIViewController{

    NSInteger barkCount;

    }

    @end

    @implementation FirstViewController

    - (void)viewDidLoad

    {

    [super viewDidLoad];

    barkCount = 0;

    [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];

    }

    -(void) updateTimer:(id) arg

    {

    barkCount++;

    if (BarkCallback) {

    BarkCallback(self, barkCount);

    }

    }

    @end

    实现block

    #import "FirstViewController.h"

    BarkCallback  = ^(FirstViewController *thisDog, int count) {

    NSLog(@"person do 1 222count %d", count);

    };

    最后,把block方法的参数来使用.(上面已经提到过)

    @interface FirstViewController : UIViewController{

    }

    //向外暴露一个接口

    -(void) setBark:( void (^) (FirstViewController *thisDog, int count) ) eachBark;

    @end

    @implementation FirstViewController

    - (void)viewDidLoad

    {

    [super viewDidLoad];

    barkCount = 0;

    [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];

    }

    -(void) updateTimer:(id) arg

    {

    barkCount++;

    }

    -(void) setBark:(void (^)(FirstViewController *, int))eachBark

    {

    eachBark(self, barkCount);

    //在这里我们直接把block回调了,其实一般不这样直接回调,一般情况是在某种动作完成后回调,比如网络请求,比如用户动作监听到以后回调,所以在这里我们可以简单改进下.

    }

    @end

    方法改进

    @interface FirstViewController : UIViewController{

    //多定义个block变量指针

    void (^BarkCallback) (FirstViewController *thisDog, int count);

    }

    //向外暴露一个接口

    -(void) setBark:( void (^) (FirstViewController *thisDog, int count) ) eachBark;

    @end

    @implementation FirstViewController

    - (void)viewDidLoad

    {

    [super viewDidLoad];

    barkCount = 0;

    [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];

    }

    -(void) updateTimer:(id) arg

    {

    barkCount++;

    //在动作完成,或者监听到用户操作时,调用这个block。这里我们是用timer定时调用.

    if (BarkCallback) {

    BarkCallback(self, barkCount);

    }

    }

    -(void) setBark:(void (^)(FirstViewController *, int))eachBark

    {

    //把实现类传过来的block指针付值给,我们定义的BarkCallback

    BarkCallback = [eachBark copy];

    }

    @end

    相关文章

      网友评论

          本文标题:Block

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