美文网首页
简单谈谈Block

简单谈谈Block

作者: conowen | 来源:发表于2017-02-07 11:32 被阅读19次
     * author:conowen@大钟                                                                                                                          
     * E-mail:conowen@hotmail.com      
    

    1、Block的定义

    Block是Objc、C、C++的一个语言级别扩充功能,Block其实就是一块代码段,你可以很方便地把一个代码段传递到不同的方法里面或者不同的类,就像传值一样方便。Block可以当做Objc里面的一个对象。(也就是说,你可以把它当做一个类似NSString的对象)

    2、Block的声明

    //As a local variable:  
    returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};  
    
    //As a property:  
    @property (nonatomic, copy, nullability) returnType (^blockName)(parameterTypes);  
    
    //As a method parameter:  
      
    - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;  
    
    //As an argument to a method call:  
    [someObject someMethodThatTakesABlock:^returnType (parameters) {...}];  
    
    //As a typedef:  
    typedef returnType (^TypeName)(parameterTypes);  
    TypeName blockName = ^returnType(parameters) {...};  
    

    上述定义来源

    http://fuckingblocksyntax.com/

    3、Block声明详解

    其实Block的定义有点类似函数指针

    引申:指针函数与函数指针的区别

    • a、指针函数
      表示函数返回值是一个指针类型,定义如下
    //类型标识符  *函数名(参数表)  
    intint *fun(x,y);  
    
    • b、函数指针
      表示指向这个函数的指针变量,定义如下
    类型标识符  (*函数名)(参数表)  
    
    int (*fun) (int x,y); //函数名前面有一个星号,然后用小括号包起来  
    fun=funTest; /* 将funTest函数的首地址赋给指针  
    

    而Block就是
    int (^fun) (int,int);

    3、Block的应用场景

    3.1、定义一个Block,然后输出打印信息

    int (^addFun)(int,int) = ^int(int a,int b){  
      
        return a + b;  
    };  
      
    NSLog(@"addValue = %d",addFun(1,2));  
    

    打印消息是
    2016-06-01 11:27:14.191 Runtime[10910:4558911] addValue = 3

    3.2、Block与Delegate的区别

    这是最简单的Block使用,一般我们使用Block来做一些有趣的事情,例如代替delegate,平常我们在不同的类传值的话,一般使用delegate,虽然也能实现,但是写法比较繁琐,用Block就能很轻松实现,而且代码量少了不少。
    下面的小Demo就依次对比了Delegate与Block在不同类的传值的区别

    第一个ViewController的代码如下

    
    //  
    //  ViewController.m  
    //  Runtime  
    //  
    //  Created by idealMac2 on 16/5/20.  
    //  Copyright © 2016年 GValley. All rights reserved.  
    //  
      
    #import "ViewController.h"  
    #import "SecondViewController.h"  
      
    @interface ViewController () <SecondViewControllerDelegate>  
      
    @end  
      
    @implementation ViewController  
      
    - (void)viewDidLoad {  
        [super viewDidLoad];  
        // Do any additional setup after loading the view, typically from a nib.  
          
          
        UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 60.0, 20.0)];  
        [btn setTitle:@"open" forState:UIControlStateNormal];  
        [btn setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];  
        [btn addTarget:self action:@selector(openAction:) forControlEvents:UIControlEventTouchUpInside];  
        [self.view addSubview:btn];  
    }  
      
    - (void)openAction:(id)sender{  
        NSLog(@"openAction");  
        SecondViewController *secondViewController = [SecondViewController new];  
        secondViewController.callBackValue =  ^ void (NSString *str){  
            NSLog(@"Block str = %@",str);  
           
        };  
        secondViewController.delegate = self;  
        [self presentViewController:secondViewController animated:YES completion:nil];  
      
    }  
      
    #pragma mark SecondViewControllerDelegate  
    - (void)closeAction:(NSString *) str{  
      
        NSLog(@"delegate str = %@",str);  
    }  
      
    - (void)didReceiveMemoryWarning {  
        [super didReceiveMemoryWarning];  
        // Dispose of any resources that can be recreated.  
    }  
      
    @end  
    

    第二个ViewController的头文件如下

    //  
    //  SecondViewController.h  
    //  Runtime  
    //  
    //  Created by idealMac2 on 16/6/1.  
    //  Copyright © 2016年 GValley. All rights reserved.  
    //  
      
    #import <UIKit/UIKit.h>  
    //声明delegate  
    @protocol SecondViewControllerDelegate <NSObject>  
      
    @optional  
    - (void)closeAction:(NSString *) str;  
      
    @end  
      
    @interface SecondViewController : UIViewController  
    //声明Block  
    @property (nonatomic,copy) void(^callBackValue)(NSString *);  
      
    @property (nonatomic,weak) id<SecondViewControllerDelegate>  delegate;  
    @end  
    

    第二个ViewController的实现文件如下

    
    //  
    //  SecondViewController.m  
    //  Runtime  
    //  
    //  Created by idealMac2 on 16/6/1.  
    //  Copyright © 2016年 GValley. All rights reserved.  
    //  
      
    #import "SecondViewController.h"  
      
    @interface SecondViewController ()  
      
    @end  
      
    @implementation SecondViewController  
      
    - (void)viewDidLoad {  
        [super viewDidLoad];  
        // Do any additional setup after loading the view.  
          
        UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 60.0, 20.0)];  
        [btn setTitle:@"close" forState:UIControlStateNormal];  
        [btn setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];  
        [btn addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside];  
        [self.view addSubview:btn];  
    }  
      
    - (void)closeAction:(id)sender{  
      
          
        NSString *strA = @"closed";  
        //Block的方式  
        self.callBackValue(strA);  
          
        //Delegate的方式  
        if (self.delegate && [self.delegate respondsToSelector:@selector(closeAction:)]) {  
            [self.delegate closeAction:strA];  
        }  
         
        [self dismissViewControllerAnimated:YES completion:nil];  
       
    }  
      
      
      
      
    - (void)didReceiveMemoryWarning {  
        [super didReceiveMemoryWarning];  
        // Dispose of any resources that can be recreated.  
    }  
      
    /* 
    #pragma mark - Navigation 
     
    // In a storyboard-based application, you will often want to do a little preparation before navigation 
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
        // Get the new view controller using [segue destinationViewController]. 
        // Pass the selected object to the new view controller. 
    } 
    */  
      
    @end  
    

    打印消息如下

    2016-06-01 12:10:31.211 Runtime[10959:4573582] block str = closed
    2016-06-01 12:10:31.211 Runtime[10959:4573582] delegate str = closed
    

    4、Block与外部变量的关系

    我们知道,Block有一个神奇之处,它可以直接使用Block之外的变量,如下面的代码。

    int c = 0;  
      
    int (^addFun)(int,int) = ^int(int a,int b){  
        return a + b + c;  
    };  
    NSLog(@"addValue = %d",addFun(1,2));  
    

    但是如果要修改外部变量,就会出现无法修改的问题,同时,使用外部变量,也会存在引起循环引用的问题。

    4.1、如何修改Block外部变量

    解决这个问题有两种方法:
    一种是C语言的方法,因为C语言中的静态变量、静态全局变量,全局变量是允许Block修改其值的。因为“全局变量” 和“ 全局静态变量” 由于作用域是全局,所以在 Block 内访问和读写这两类变量和普通函数没什么区别。但是“ 静态变量” 作用域在 block 之外,那Block是怎么对它进行读写呢?其实“静态变量” 是通过指针传递,将变量传递到 Block 里面,所以可以修改变量值。普通的非全局变量,都是通过传值进去Block里面,当然无法修改这个变量的值。

    如下面的代码

    static int c = 0;//静态变量  
      
    int (^addFun)(int,int) = ^int(int a,int b){  
        c = 1;  
        return a + b + c;  
    };  
    NSLog(@"addValue = %d",addFun(1,2))  
    

    还有一种方法就是通过在变量外部加上“__block”说明符,其实加了__Block之后,这个变量就变成了一个结构体指针变量,这个原理和静态变量一样,由传值方式改为指针传递,所以就可以更改变量了。
    如下所示

    
    __block int c = 0;  
      
    int (^addFun)(int,int) = ^int(int a,int b){  
        c = 1;  
        return a + b + c;  
    };  
    NSLog(@"addValue = %d",addFun(1,2));  
    

    4.2、如何避免Block的循环引用

    ** 待补充**

    相关文章

      网友评论

          本文标题:简单谈谈Block

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