zoukankan      html  css  js  c++  java
  • block

    1.block

      1. 什么是block
        block说简单了就是一个数据类型,里面存放一段代码.但是编译器不去执行,只有到用到的时候才去执行block内部的代码.
        block的标志就是^.

      2. 如何去定义block呢
        下面定义一个最简单的block                                                          

    // 既然是一种数据类型,那么,我们就定义一个名叫myBlock的block.它的数据类型是void(^)(),  myBlock 是变量名
    // 比较特殊的地方在于,变量名在中间,不是在后面
    // 下面这个这是定义了一个无返回值,无参数的block
    // 要注意的是block是以^开头,结束要以分号(;)结束
    void(^myBlock)() = ^{
    NSLog(
    myBlock();
    // 调用完成之后,才真正会走myBlock里面的代码.
    // 这时才会打印myBlock
    
    // 无参有返回值
    int(^myBlock1)() = ^{
        return 2;
    };
    int result = myBlock1();
    NSLog(@"%d", result);
    
    // 有参有返回值
    int (^myBlock2)(int, int) = ^(int a, int b){
        return a + b;
    };
    
    int result1 = myBlock2(3, 4);
    NSLog(@"%d", result1);


    当然为了书写方便,有时候我们会使用重命名

    typedef void(^MyBlock)(); // 定义一个无参无返回值,类型名为MyBlock的block.
    
    // 这样使用起来和我们定义变量很像了
    // 但是实际由于我们使用block的目的性,所以不去这么写
    MyBlock block = ^{};

    修改block内部变量
    如果一个变量实在block外部声明的,需要在block内部修改变量.那个该变量不能直接使用.而是要加__block进行修饰

     // 如果不加block, block内部修改变量会报错
           __block int value = 5;
    
           void(^myBlock)() = ^{
               value = 10;
            };
    
            NSLog(@"%d", value); // 5
    
            myBlock();
    
            NSLog(@"%d", value); // 10



    上面这个例子也能证明,只有在调用block之后,block中的代码才会被执行.当然我们也可以使用__weak.
    需要注意的是

    1. __block不管在ARC还是MRC环境下都可以使用,可以修饰对象,也可以修饰基本数据类型
    2. __weak只能用于ARC环境下,只能修饰对象,不能修饰基本数据类型

    上面看到的都是block的语法.有时候只是看了语法,其实并不知道做什么用.下面可以用简单的例子来说明一下. 看看block方便之处.如果对于反向传值了解的话就会很容易看出来好处了.要比使用委托模式简单的多

    ViewController.m 文件

    #import "ViewController.h"
    #import "testViewController.h"
    
    @interface ViewController ()
    
    @property (nonatomic, weak) UILabel *label;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
        label.backgroundColor = [UIColor grayColor];
        [self.view addSubview:label];
        self.label = label;
    
    
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        testViewController *testVc = [[testViewController alloc] init];
        testVc.callback = ^(NSString *string){
            self.label.text = string;
        };
        [self presentViewController:testVc animated:YES completion:nil];
    
    }
    
    @end

    testViewController.h文件

    testView
    #import <UIKit/UIKit.h>
    
    typedef void(^CallBack)(NSString *);
    
    @interface testViewController : UIViewController
    
    @property (nonatomic, copy) CallBack callback;
    
    @end

    testViewController.m文件

    #import "testViewController.h"
    
    @interface testViewController ()
    
    @property (nonatomic, weak) UITextField *textField;
    
    @end
    
    @implementation testViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor blueColor];
        UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(20, 20, 100, 40)];
        textField.borderStyle = UITextBorderStyleLine;
        [self.view addSubview:textField];
        self.textField = textField;
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        self.callback(self.textField.text);
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    @end

    大家可以回想一下,如果使用委托模式的话需要制订协议,最受协议,设置代理....这个是不是要方便的多啊.

    当然最常用的还是使用在block作为参数传值.最大的好处是可以在不同的情况下回调不同的代码.

    下面只是举个栗子

    +(void)loadImageName:(NSString *)imagename succedBlock:(SuccedBlock)succedBlock  failBlock:(FailBlock)failBlock{
        UIImage *image = [UIImage imageNamed:imagename];
        if (image) {
    
            succedBlock(image);
        } else {
    
            NSError *error;
            failBlock(error);
    
        }
    }

    这种方式在网络请求中很常用,而已很简单的得到请求返回数据是否成功,在请求方法里的代码逻辑性更强.

    在使用block要避免循环引用的问题.至于什么时候会出现这种问题,最简单的就是,在block用到当前的对象的属性值.
    下面的例子可能不太适当,但是可以说明问题

    typedef void(^Block)();
    
    @interface Person ()
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) Block block;
    
    @end
    
    @implementation Person
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            _block = ^{
                self.name = @"zhangsan";  // 这句话会有这个警告 Capturing 'self' strongly in this block is likely to lead to a retain cycle
            };
    
            _block();
        }
        return self;
    }
    
    @end

    那么应该如何处理呢.

    // 在block将 self 定义为弱引用,在block中使用弱引用
    __weak typeof(self) weakSelf = self;

    若果需要更深入的了解block的话
    我们可以在终端里输入如下的命令,将项目以C++重写.这样我们就可以看到block的底层构造了

  • 相关阅读:
    Linux操作_常用命令操作练习
    Linux编程_Shell脚本练习题
    Linux操作_grep/egrep工具的使用
    Linux中的链接文件_软链接和硬链接
    Linux操作_磁盘管理_增加虚拟磁盘
    Linux命令_磁盘管理_查看磁盘或目录的容量
    Linux命令_用户身份切换
    使用Unity中的Box Collider组件完成游戏场景中的碰撞检测功能
    在Unity场景中更改天空盒的步骤
    Linux命令_用户和用户组管理
  • 原文地址:https://www.cnblogs.com/liuzhi20101016/p/5203772.html
Copyright © 2011-2022 走看看