block的使用

作者: cyh老崔 | 来源:发表于2015-12-17 22:10 被阅读234次

内容:

  • block的定义
  • block的使用
  • block的内存管理

一.block的定义

定义变量和定义属性相同

  • 将block想象成变量,如 int 变量,原理相同.

1.定义block属性

/** 定义block属性, sumBlock为参数名 */
@property (nonatomic, copy) int (^sumBlock)(int, int);

2.定义block方法

/** 定义block方法:无参无返回值 */
    void (^myBlock)() = ^{
        NSLog(@"test");
    };
    
/** 定义block方法:有参有返回值 */
    int (^sumBlock)(int, int) = ^(int num1, int num2){
        return num1 + num2;
    };
    int sum = sumBlock(2, 3);
}

3.block作为参数


//定义block参数:参数名称写在外面(如int参数,参数名称也是写在外面)
- (void)test2:(int (^)(int, int))sumBlock{

}

4.block作为返回值


//定义block返回值
- (int (^)(int, int))test3{
    return nil;
}

typedef简化定义block

typedef void(^resultBlock)(NSArray<Person *> *arr);

二. block的使用

使用场景一:传值

控制器A modal 出控制器B, B向A传值(逆传)

  • 步骤1, B控制器中新建两个属性
/** 逆传 strNi */
@property (nonatomic, strong) NSString *strNi;

/** 逆传 block */
@property (nonatomic, strong)  void(^block)(NSString *strNi);
  • 步骤2, B控制器中,在适当的时候传值
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    if (_block) {
        _block(_strNi);
    }
}
  • 步骤3, A控制器中, 接收数据
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    FanLuModalController *Bvc = [FanLuModalController alloc] init];

    //逆传
    Bvc.block = ^(NSString *str){ //str即为B控制器传过来的值
      
        NSLog(@"strNi from Bvc = %@", str);
    };
}

使用场景二: 作为参数

  • 让他人决定执行的代码
  • 自己决定代码执行的时机:或立即执行,或保存起来,等待合适的时机执行.

-- 定义block方法的类

FLCalculatorManager.h

/** calculate result */
@property (nonatomic, assign) int result;

- (void)calculator:(int(^)())block;

FLCalculatorManager.m

- (void)calculator:(int(^)())block{

    _result = block();
    
}

-- 另外一个类:调用这个calculator:方法,传入block

    FLCalculatorManager *manager = [[FLCalculatorManager alloc]init];
    
    [manager calculator:^int{
        
        return 5;
    }];

使用场景三: 作为返回值,生成链式编程(一般只有在框架中才会使用).如:

make.equalTo(superview).with.insets(padding);
  • 链式编程思想:把多个方法用点语法方式连接起来. 优点:可读性非常好.
  • 原理解析:
  • 点语法就是调用get方法. 每一次点语法, 都是返回一个对象; 接着再用这个对象, 通过点语法调用当前对象的get方法.
注: get方法: 只要是没有参数, 且有返回值的方法,都是get方法.
  • 调用get方法 例子:

- (void)viewDidLoad {
    [super viewDidLoad];
    
   //调用返回值为block的get的方法:test.
    self.test();
}

- (void(^)())test{

    return ^{
        NSLog(@"平凡而已");
    };
}
  • 链式编程例子: 通过链式多次相加, 求得最终的result

  • 重点:

  • 生成一个返回值是block的get方法

  • 此block的返回值是当前对象, 有一个参数以参与加法运算.

  • 类:FLCalculatorManager.h

/** 最终结果 */
@property (nonatomic, assign) int result;

//返回值是一个block---CalculatorManager *(^)(int),
//这个block的返回值是一个对象---"CalculatorManager *",且这个block需要一个int参数
- (FLCalculatorManager *(^)(int))add;
  • 类:FLCalculatorManager.m
- (FLCalculatorManager *(^)(int))add{
    
    //下面代码解析:
    //第一个return:返回一个返回值是当前对象的block,是代码块.这个return即是当前方法最终的return
    //第二个return:block中的return,返回当前对象
    return ^FLCalculatorManager *(int value){
        
        _result += value;
        return self;
    };
}
  • 类控制器调用:
    FLCalculatorManager *manager = [[FLCalculatorManager alloc]init];

    //调用manager的返回值是block的get方法:add,虽然add方法没有参数,但是其block需要参数    manager.add(10).add(10).add(20);
    
    NSLog(@"result = %d", manager.result);  //result最终 == 40

三. block的内存管理

  • block:会对 自己代码块中的 外部的 强指针变量 强引用.所以经常使用下句代码, 以防止循环利用:
    __weak typeof(self) weakSelf = self;
  • 但是如果控制器销毁后, 需要执行的任务还没有执行, 此时我们需要进一步处理:
__strong typeof(weakSelf) strongSelf = weakSelf;
  • 下demo是控制器点击时即销毁, 而此时我们还有异步或延迟操作.
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self dismissViewControllerAnimated:YES completion:nil];
}
 // block:会对自己代码块中的,外部强指针变量强引用
    __weak typeof(self) weakSelf = self;
    
    _block = ^{
        
        // block比如做一些异步操作/延迟操作
        __strong typeof(weakSelf) strongSelf = weakSelf;
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            
            NSLog(@"打印%@",strongSelf);
        });
    };

    _block();
}
  • block访问block之外的变量
int main(int argc, const char * argv[]) {
    @autoreleasepool {
   
        __block int a = 3;

// 1.如果a没有__block修饰,且已经传进方法,外面再修改a的值,block内部a的值不会改变. 
    //因为block会以const的形式将a拷贝到堆区,即block不可以修改外部变量。
// 2.默认block引用外部的局部变量,并且没有任何关键字修饰,都是值传递
// 3.如果外部变量用__block或者static修饰,就是指针传递,外面改了,里面也会改
// 4.只要是全局变量,Block中也是指针传递,可以修改变量
- (void)test{
            void(^block)() = ^{
            
            NSLog(@"%d",a);
            };
        
            a = 5;
            block(); 
   }

MRC与ARC中block的比较

  • 在MRC开发中,不能使用下划线成员属性,应该使用get,set方法对属性进行操作.

  • block:strong:ARC, copy:MRC

  • block是对象,所以使用%@打印.

  • MRC:管理block:

  • 1.如果block没有访问外部的局部变量,或者访问的变量被static修饰,或者访问全局变量,那么这个block就是全局的.

  • 2.如果block访问外部的局部变量,那么这个block在栈中.

  • 3.block如果想保存到堆里面,只能使用copy,不能使用retain.因为使用retain系统还是保存block在栈里面.

  • ARC: block保存在堆中.

相关文章

  • ios block使用

    iOS Block的使用一 .最简单的block使用******使用block的三个步骤:1.定义block变量 ...

  • 白话block

    本文内容 什么是block? block的用途 block的用法 block在使用中遇到的问题 如何使用xcode...

  • iOS Block使用注意

    block本质是两个结构体,使用block使代码简单易读。使用Block注意: 1、block内部使用外部指针,会...

  • iOS Block -浅析 文章

    Block 的使用有两种:1.独立Block 。2.内联Block 。 《一》独立Block 使用方式 一、定义一...

  • OC中的block回顾

    1.block声明 2.block的typedef 2.1 typedef的使用 2.2 声明block类型的使用...

  • Block其实很简单

    Block的几种情况 block的使用 1.使用block实现反向传值 2.利用block写响应式编程的技巧

  • Objective-C 类之间通信

    block的使用 block的定义和使用 变量的作用域及代码的执行顺序 block外部变量的值在block内部具有...

  • Blocks

    使用block修改器 __block

  • iOS开发--当Block、代理、通知遇到女朋友

    什么是Block? 为什么使用Block? 怎么使用Block? 本文将从这三个问题入手来逐渐了解Block。 本...

  • block使用及其底层原理

    一 block基本使用 二 block底层结构 三 block变量捕获 四 block的类型 五 block对象类...

网友评论

    本文标题:block的使用

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