Block基本用法

Block在iOS开发中使用频率非常高, 现总结一篇block基本用法和大家分享一下!

声明

  • 声明格式: 返回值(^block变量名)(参数); 变量名可有可无

    void(^block1(int a)
    void(^block2)(int);
    
  • 声明blocks属性: ARC模式下用strong, MRC模式下用copy

    @property(nonatomic ,strong) void(^block)();
    

定义

定义格式: = ^返回值(参数), 可以使用快捷键inline, 如果没有参数或者返回值, 返回值和参数都可以省略

  • 第一种方式

    void(^block1)() = ^void(){
    NSLog(@"第一种定义方式");
    };

  • 第二种方式

    void(^block2)() = ^()
    {
    NSLog(@"第二种定义方式");
    };

  • 第三种定义方式

    void(^block3)() = ^
    {
    NSLog(@"第三种定义方式");
    };


作用

和函数功能相似, 保存一段代码.


调用

block的调用是直接去调用的.

block();

应用场景一: 保存代码

  1. 在Person类中定义一个block属性

    @property(nonatomic ,strong) void(^programmer)();
    
  2. 在tableViewController类中定义block

    Person *person1 = [[Person alloc] init];
    person.programmer = ^{
        NSLog(@"健身");
    };
    
    Person *person2 = [[Person alloc] init];
    person.programmer = ^{
        NSLog(@"读书");
    };
    
    Person *person3 = [[Person alloc] init];
    person.programmer = ^{
        NSLog(@"撸代码");
    };
    
    //添加进persons数组
    self.persons = @[person1,person2,person3];
    
  3. 在cell数据源方法中调用

    Person *person = self.persons[indexPath.row];
    
    if (Person.programmer) {
    Person.programmer();
    }
    

应用场景二: 传值

传值有两种情况:

  • 顺传: 上一个控制器给下一个控制器传值. 可以直接在下一个控制器中定义属性来传值.
  • 逆传: 下一个控制器给上一个控制器传值. 可以使用代理, 也可以使用block. 由于block的方便和易用性, 开发中使用block的较多些.
  1. 在下一个控制器中定义一个block属性: 参数就是下一个控制器需要传给上一个控制器的值

     @property (nonatomic, strong) void(^valueBlock)(NSString *);
    
  2. 在下一个控制器中定义block, 把值传进去

     if (_valueBlock) {
      //括号里面就是要传的值
     _valueBlock(@"这就是要传的值");
      }
    
  3. 在上一个控制器中调用block, 把参数传进来, value就是下一个控制器传给上一个控制器的值(也就是逆传的值)

     nextVC.valueBlock = ^(NSString *value){
     NSLog(@"这就是需要传的值%@",value);
      };
    


应用场景三: block作为参数

block作为参数, 一般在框架中使用较多.

  • 内部: 首先定义一个属性, 把block参数保存起来, 在合适的地方调用. 或者是直接在当前方法中调用用.
  • 外界: 定义block, 在block中做一些操作

例如: 封装一个加法类

  1. 在Add类中定义一个带有block参数的方法

    @property (nonatomic, assign) int result;
    
    // int(^(int): 参数类型
    -(void)add(int(^(int))addBlock;
    
  2. 在外部controller类中定义block. 外界可以在block中随意做一些操作, 这些操作的结果都会作为参数传给内部

    Add *add = [[Add alloc] init];
    
    [add add:^int(int result){
    
            //在这里面做一些操作
            result += 10;
            return result;
     }];
    
  3. 在Add类中调用block, 可以直接调用. 也可以先保存起来, 再在合适的地方调用

    - (void)add:(int (^)(int))addBlock
    {
        _result = addBlock(_result);
         NSLog(@"%i",_result);
    
    }
    


应用场景四: block作为返回值

  1. 在Add类定义声明一个返回值为block的方法

    @property (nonatomic, assign) int result;
    
    - (void(^)(int value))add;
    
  2. 在外部类中调用block

    Add *add = [[Add alloc] init];
    
    add.add(5);
    
  3. 在Add类中实现方法

    - (void (^)(int value))add
    {
    	return ^(int value){
    		  _result += value;
    	  };
    }
    

Block注意问题

1. 循环引用问题

block会把外界的强指针强引用
默认局部变量都是强指针

	__weak typeof(self) weakSelf = self;
	
	typeof(self) strongSelf = weakSelf;

2. 变量引用问题

bock引用变量: 全局变量,静态变量,__block都是指针传递. 局部变量是值传递

释义:
默认block引用外部的局部变量,并且没有任何关键字修饰,都是值传递
如果外部变量用__block或者static修饰,就是指针传递,外面改了,里面也会改
只要是全局变量,Block也是指针传递

3. 内存管理

MRC
block没有访问外部变量,在全局区
如果访问了外部变量,默认block在栈中
MRC中用copy, block才会放在堆中保存.

释义:

  1. 如果block没有访问外部的局部变量,或者访问的变量被static修饰,或者访问全局变量,那么这个block就是全局的
  2. 如果block访问外部的局部变量,那么这个block在栈里面的.
  3. block如果想保存到堆里面,只能使用copy,不能使用retain,使用retain还是在栈里面.

ARC
如果访问了外部变量,默认block在堆中

释义:

  1. 如果block访问外部的局部变量,那么这个block在堆里面的.
  2. 在ARC中,block使用strong,放在堆里面保存
  3. 能使用strong,就不要使用copy.

内存中几个区

全局区:保存全局变量
常量区:保存常量
堆:手动去管理内存,对象
栈:基本变量,int,指针,自动管理
方法区:保存函数


posted @ 2016-01-01 20:25  小白杂货铺  阅读(205)  评论(0编辑  收藏  举报