Block常用知识点总结

作者: 小码码 | 来源:发表于2017-03-28 16:33 被阅读61次

    对于刚入门iOS的小菜鸟来说,block总显得那么晦涩难懂,即使一时了解了,开发中也总找不到使用的场景,甚至是不愿意用,时间久了可能连其格式都忘了。本文为了加强记忆,也为了日后自己用起来方便,稍微总结了block的基本知识和应用。

    1 block的基础知识

    参考文章:http://www.jianshu.com/p/d28a5633b963

    1.1 基本格式

    (1) 完整写法
    ^ 返回值类型 (参数列表) {表达式}

    ^ int (int count) {
            return count + 1;
        };
    

    (2) 省去返回值类型
    ^ (参数列表) {表达式}

     ^ (int count) {
          return count + 1;
      };
    

    (3)参数列表为空时, 省去参数列表
    ^ {表达式}

     ^ {
          NSLog(@"No Parameter");
      };
    

    1.2 定义block变量

    返回值类型 (^变量名)(参数列表) = Block表达式

    // 声明了一个变量名为blk的Block:
     int (^blk)(int) = ^(int count) {
            return count + 1;
        };
    

    1.3 定义block属性(ARC下用strong)

    (1)直接定义
    @property (nonatomic, strong) void(^block)();

    (2)用别名定义
    取别名:
    typedef void(^BlockName)();
    用别名定义属性:
    @property (nonatomic, strong) BlockName block1;

    1.4 block的循环引用

    参考文章:
    http://www.jianshu.com/p/b1f49e287f19
    http://www.jianshu.com/p/53cedd7bafa4
    解决办法:
    (1) __weak typeof(self) weakSelf = self; block中的self用weakSelf代替
    (2) 使用weakSelf结合strongSelf的情况下,能够避免循环引用,也不会造成提前释放导致block内部代码无效。

     __weak typeof(self) weakSelf = self;
        
        _block = ^{
            // block代码不管有没有调用,只要访问外部强引用变量,就会把变量给在强引用
            // block会对外界的强指针给强引用一次
            __strong typeof(weakSelf) strongSelf = weakSelf;
            
       dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
               
                // 必须要拿到self做事情,strongSelf没有释放(有值),但又不会造成循环引用
                 NSLog(@"%@",strongSelf);
                
            });
            
        };
    

    1.4 __block说明符号

    (1)截获自动变量值

    int i = 10;
        void (^blk)(void) = ^{
            NSLog(@"In block, i = %d", i);
        };
        i = 20;//Block外修改变量i,也不影响Block内的自动变量
        blk();//i修改为20后才执行,打印: In block, i = 10
        NSLog(@"i = %d", i);//打印:i = 20
    

    (2)__block变量
    自动变量截获的值为Block声明时刻的瞬间值,保存后就不能改写该值,如需对自动变量进行重新赋值,需要在变量声明前附加__block说明符,这时该变量称为__block变量

    __block int i = 10;//i为__block变量,可在block中重新赋值
        void (^blk)(void) = ^{
            NSLog(@"In block, i = %d", i);
        };
        i = 20;
        blk();//打印: In block, i = 20
        NSLog(@"i = %d", i);//打印:i = 20
    

    (3)修改对象的属性
    当自动变量为一个类的对象,且没有使用__block修饰时,虽然不可以在Block内对该变量进行重新赋值,但可以修改该对象的属性。
    如果该对象是个Mutable的对象,例如NSMutableArray,则还可以在Block内对NSMutableArray进行元素的增删

      NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"1", @"2",nil ];
        NSLog(@"Array Count:%ld", array.count);//打印Array Count:2
        void (^blk)(void) = ^{
            [array removeObjectAtIndex:0];//Ok
            //array = [NSNSMutableArray new];//没有__block修饰,编译失败!
        };
        blk();
        NSLog(@"Array Count:%ld", array.count);//打印Array Count:1
    

    2 block的四种常用场景

    参考文章:http://www.jianshu.com/p/f0f35b87af86

    2.1 作为属性保存代码

    typedef void(^BlockName)();
    @interface ViewController ()
    // block类型:void(^)()
    @property (nonatomic, strong) BlockName block;
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
           void(^block)() = ^{
            NSLog(@"调用了Block");
        };
          // 保存代码
        _block = block;   
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    { 
         // 调用block
         _block();
    }
    

    2.2 作为参数

    - (void)calcutor:(NSInteger (^)(NSInteger))cacultorBlock
    {
        if (cacultorBlock) {
           _result = cacultorBlock(_result);
        }
    }
    

    2.3 作为返回值

    // CacultorManager:自定义的一个工具类,也可以为常规的返回值类型
    - (CacultorManager * (^)(NSInteger))add
    {
        return ^(NSInteger value){
            
            _result += value;
            
            return self;
        };
    }
    

    2.4 逆向传值

    参考文章:http://www.jianshu.com/p/7d729fc351c8

    传值方:

    //.h 文件
    
    /**
     *  类型自定义
     */
    typedef void (^ReturnValueBlock) (NSString *strValue);
    
    @interface NextViewController : UIViewController
    /**
     *  声明一个ReturnValueBlock属性,这个Block是获取传值的界面传进来的
     */
    @property(nonatomic, copy) ReturnValueBlock returnValueBlock;
    
    @end
    
    =================================================================
    
    //.m 文件
    
    #import "NextViewController.h"
    
    @interface NextViewController ()
    
    @property (weak, nonatomic) IBOutlet UITextField *inputText;
    
    - (IBAction)back:(id)sender;
    
    @end
    
    @implementation NextViewController
    
    - (void)viewDidLoad {
    
        [super viewDidLoad];
    
        self.navigationItem.title = @"第二个界面";
    }
    
    
    /**
     *  返回上一个界面
     *
     *  @param sender 按钮
     */
    - (IBAction)back:(id)sender {
    
        NSString *inputString = self.inputText.text;
    
        if (self.returnValueBlock) {
            //将自己的值传出去,完成传值
            self.returnValueBlock(inputString);
        }
    
        [self.navigationController popViewControllerAnimated:YES];
    
    }
    
    @end
    

    捕获方:

    //.m 文件
    
    #import "ViewController.h"
    #import "NextViewController.h"
    
    @interface ViewController ()
    
    @property (weak, nonatomic) IBOutlet UILabel *nextPassedValue;
    
    - (IBAction)next:(id)sender;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    
        [super viewDidLoad];
    
    }
    
    //点击按钮跳转到第二个界面
    - (IBAction)next:(id)sender {
    
        NextViewController *nvc = [[NextViewController alloc]init];
    
        //赋值Block,并将捕获的值赋值给UILabel
        nvc.returnValueBlock = ^(NSString *passedValue){
    
            self.nextPassedValue.text = passedValue;
    
        };
    
        [self.navigationController pushViewController:nvc animated:YES];
    
    }
    @end
    

    3 Block实现原理

    对于想理解Block底层原理的开发者,可以参考以下文章:
    http://www.jianshu.com/p/d28a5633b963
    http://www.jianshu.com/p/404ff9d3cd42
    http://www.jianshu.com/p/ee9756f3d5f6

    相关文章

      网友评论

      • wg689:大神,又在写博客啊 超赞

      本文标题:Block常用知识点总结

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