iOS之block基本使用

作者: 追逐_chase | 来源:发表于2017-09-29 10:54 被阅读59次

    block在iOS日常开放中已经越来越受欢迎了,小结一下,填补之前遇到的坑

    block

    • block的作用:是用来保存一段代码片段
    • block声明: 返回值 (^变量名)(参数);
    • block的类型:
    类型为:int(^)(NSString *)
    int(^block)(NSString *) = ^(NSString *name) {
    
    };
    
    • block的定义(3中方式)= ^(参数){}
    //方式1  正常
    void(^myBlock1)() = ^(){
        NSLog(@"第一种方式");
    };
    
    //方式2  如果没有参数,参数可以隐藏,如果有参数,定义的时候,必须要写参数,而且必须要有参数变量名
    void(^myBlock2)(int) = ^(int a){
            NSLog(@"第二种方式");
     };
    
    //方式3 block返回可以省略,不管有没有返回值,都可以省略
    int(^myBlock3)() = ^int{
            return 3;
        };
    
    
    • block的调用
    //比如说调用第一个
    myBlock1();
    
    • block是对象,
    • 只要block没有引用外部局部变量,block放在全局区
    • MRC: block在MRC环境下
      • block:只要引用外部局部变量,block放在栈里面
      • block只能使用copy,不能使用retain,使用retain,block还在栈里面,在访问的时候内存销毁,会报坏内存错误
    • ARC: block在ARC环境下
      • 只要block引用外部局部变量,block放在堆里面
      • block使用strong修饰,最好不用copy
    block使用场景
    1、定义在一个方法在另外一个方法中调用(不常用)
    2、在一个类中定义,在另外一个类中调用(常用),用block保存代码到模型中
    例子:在控制器里面定义一个tableView,在定义一个模型model,
    #import "ViewController.h"
    #import "cellModel.h"
    
    @interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
    
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    @property (nonatomic, strong) NSArray *itemModels;
    
    @end
    
    
    - (void)viewDidLoad {
       [super viewDidLoad];
     
    //模型
       cellModel *model1 = [cellModel itemWithString:@"标题1"];
       model1.cellBlock = ^{
           
           NSLog(@"点击标题1了");
       };
       cellModel *model2 = [cellModel itemWithString:@"鸟啼2"];
       model2.cellBlock = ^{
           NSLog(@"点击标题2了");
       };
       cellModel *model3 = [cellModel itemWithString:@"标题3"];
       model3.cellBlock = ^{
             NSLog(@"点击标题3了");
       };
       self.itemModels = @[model1,model2,model3];
    
    }
    
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
       
       return 3;
    }
    
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
       
       static NSString *ID = @"ID";
       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
       
       if (cell == nil) {
           cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
       }
       
       cellModel *model = self.itemModels[indexPath.row];
       
       cell.textLabel.text = model.title;
       
       
       return cell;
       
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
       
       [tableView deselectRowAtIndexPath:indexPath animated:YES];
       
       cellModel *model = self.itemModels[indexPath.row];
    //判断是否存在
       if (model.cellBlock) {
             model.cellBlock();
       }
      
    }
    
    ### 模型###
    
    #import <Foundation/Foundation.h>
    @interface cellModel : NSObject
    
    /** 名称*/
    @property (nonatomic, strong) NSString *title;
    
    /** 保存代码的block */
    @property (nonatomic, strong) void(^cellBlock)(void);
    
    +(instancetype)itemWithString:(NSString *)title;
    
    @end
    
    
    
    #import "cellModel.h"
    
    @implementation cellModel
    
    +(instancetype)itemWithString:(NSString *)title {
       cellModel *model = [[self alloc] init];
       model.title = title;
       
       return model;
    }
    
    @end
    
    

    打印结果

    block打印.png

    block变量传递

    //如果是局部变量的话,block是值传递
    - (void)viewDidLoad {
       [super viewDidLoad];
       
       int a = 3;
        //如果是局部变量的话,block是值传递
    
       void(^block)(void)=^{
          
           NSLog(@"%zd",a);
       };
    //调用
       block();
    打印的结果:a= 3;
    
     //如果是静态变量/全局变量/__block修饰的变量,block是指针传递
    
    //全局变量
    int a = 3;
    - (void)viewDidLoad {
       [super viewDidLoad];
    //static int a = 3;  //静态变量
      __block  int a = 3;
        //如果是局部变量的话,block是值传递
       void(^block)(void)=^{
           NSLog(@"%zd",a);
       };
       a = 5;
    block();
    打印的结果是:a = 5;
    }
    
    

    block传值

    //block传值也是普遍使用的 和delegate传值其他效果是一样的(都是逆传)
    //有2个控制器VC 
    *************************例子************************
    
    #import "ViewController.h"
    #import "BlockValueVC.h"
    
    @interface ViewController ()
    
    @end
    
    
    @implementation ViewController
    
    - (void)viewDidLoad {
       [super viewDidLoad];
       self.view.backgroundColor = [UIColor redColor];
       
    }
    
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
       BlockValueVC *modalVc = [[BlockValueVC alloc] init];
       modalVc.view.backgroundColor = [UIColor brownColor];
       modalVc.block = ^(NSString *value) {
         
           NSLog(@"传值结果:%@",value);
       };
       
       // 跳转
       [self presentViewController:modalVc animated:YES completion:nil];
    }
    
    //在BlockValueVC控制器中定义block 
    #import <UIKit/UIKit.h>
    @interface BlockValueVC : UIViewController
    @property (nonatomic, strong) void(^block)(NSString *value);
    
    @end
    
    //在BlockValueVC.m文件中使用
    
    #import "BlockValueVC.h"
    
    @interface BlockValueVC ()
    
    @end
    
    @implementation BlockValueVC
    
    - (void)viewDidLoad {
       [super viewDidLoad];
       // Do any additional setup after loading the view.
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
       // 传值给ViewController
       // @"123"
    //判断是否存在 调用Block
       if (_block) {
           _block(@"123");
       }
      
    }
    
    //打印结果
    
    传值结果: 123
    
    

    block循环引用

    #import "ViewController.h"
    
    #import "VC.h"
    @interface ViewController ()
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
       [super viewDidLoad];
       self.view.backgroundColor = [UIColor redColor]; 
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
       VC *vc = [[VC alloc] init];
       [self presentViewController:vc animated:YES completion:nil];
       
    }
    @end
    
    
    **************************VC控制器**************************
    
    #import "VC.h"
    
    @interface VC ()
    
    @property (nonatomic, strong) void(^block)(void);
    
    @end
    
    @implementation VC
    
    - (void)viewDidLoad {
       [super viewDidLoad];
       
       self.view.backgroundColor = [UIColor purpleColor];
       
       _block = ^{
           
           NSLog(@"看看对象:%@",self);
           
       };
       
       _block();
       
       
    }
    
    - (void)dealloc {
       
       NSLog(@"控制器是否销毁");
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
       
       [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    //打印结果
    
    017-10-09 11:43:23.300091+0800 04-Block的循环引用[3404:119114] 看看对象:<VC: 0x7fdcaf524040>
    
    //控制器并没有销毁
    //原因:下图
    
    block循环图.png
    解决方法
    // block造成循环利用:Block会对里面所有强指针变量都强引用一次
    //  __weak typeof(self) weakSelf = self;
    //我们在VC控制器里面的viewDidLoad方法中进行修改
    
    
    
    - (void)viewDidLoad {
       [super viewDidLoad];
     
       __weak typeof(self) weakSelf = self;
       
       _block = ^{
          NSLog(@"%@",weakSelf);
       };
       
       _block();
    }
    
    
    //打印结果
    017-10-09 11:43:23.300091+0800 04-Block的循环引用[3404:119114] 看看对象:<VC: 0x7fdcaf524040>
    017-10-09 11:43:23.300091+0800 04-Block的循环引用[3404:119114] 控制器是否销毁
    
    
    //注意:如果在block中在使用block需要是使用   __strong typeof(weakSelf) strongSelf = weakSelf;
    
    - (void)viewDidLoad {
       [super viewDidLoad];
       // Do any additional setup after loading the view.
       // block造成循环利用:Block会对里面所有强指针变量都强引用一次
       
       __weak typeof(self) weakSelf = self;
       
       _block = ^{
    
       //防止循环引用
          NSLog(@"%@",weakSelf);
    
     //防止_block内部的block在访问weakSelf对象的时候销毁
         __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作为参数使用

    //这样的使用方式很多,比如AFN网络请求时
    //后续补上
    
    

    相关文章

      网友评论

        本文标题:iOS之block基本使用

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