快速理解Block

作者: 花间刺客 | 来源:发表于2017-03-03 09:02 被阅读47次
block
block的作用:保存一段代码,不是马上执行,需要调用。
快速生成block代码:inlineBlock
最简单的block:void(^block)()
block是一个对象,详见官方文档搜索working with blocks
block的几种类型及写法
调用block

调用block方式block名称(参数)

e.g.

注意点:1、声明block属性时,不同于其他数据类型+变量名形式,直接写block类型,但用typedef定义一个block类型的别名也可以实现常见的的数据类型+变量名形式,如上图黄色框所示。2、block必须用strong

使用场景:传值

从下一个控制器传到上一个控制器可以代理,在传值的控制器中设置代理,在需要传值的控制器中遵守代理协议方法;逆传时,也可以利用block可以携带参数的特性替代代理方法传值。
简单举个例子创建A、B两个控制器,A present 到B,在B dismiss 时传值,在此之前先在B声明一个带参数的block属性,在A中定义这个block,再在A中调用这个block。

总结
  1. 声明一个带参数的block属性
  2. 在需要传值的block中定义block
  3. 在传值控制器中调用block

传值注意点:在传值时,为了安全起见,要先判断是否定义了block,或是是否响应了代理方法。

Block的内存管理

MRC:

  1. 如果block访问外部局部变量,block存放在栈中;
  2. 在MRC中不能使用retain声明block,依然放在栈里面,会自动销毁;
  3. 使用copy声明block,才会放在堆里面
ARC

如果block访问外部的局部变量,block存放在"堆"里面
ARC:使用strong声明block,不要使用weak

(p.s.) ARC管理原则:默认一个局部变量对象,都是强指针,存放堆里面
ARC:如果一个对象没有强指针引用,就会销毁

block管理原则

如果block没有访问外部的局部变量或者局部变量被static修饰,block默认存放在"全局区"
(e.g.)
int a = 2; void(^block)() = ^{ NSLog(@"%d",a); }; _block = block; a = 4; NSLog(@"%@",block);打印结果为2;在变量a前加入static打印结果为4;

block循环引用

注意点:

  1. block会对外部所有强指针对象强引用
  2. block不会对外部弱指针对象给强引用
    (e.g.)
    @interface ModalViewController () @property (nonatomic, strong) void(^block)(); @end

block = ^{ NSLog(@"%@",self); }
(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self dismissViewControllerAnimated:YES completion:nil]; }

- (void)dealloc { NSLog(@"%s",__func__); }
ModalViewController dismiss后dealloc并未打印,表明控制器并未销毁,问题出在block块中NSLog(@"%@",self);self强引用了ModalViewController造成循环引用,如下图:


解决办法:声明weakSelf弱指针__weak typeof(self) weakSelf = self;(block不会对外部弱指针对象给强引用)
(e.g.)
如果在block代码块中加入延迟或者异步操作时
__weak typeof(self) weakSelf = self; _block = ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%@", weakSelf); }); }; _block();代码块中weakSelf打印为null
解决办法:在afterBlock外部添加strongSelf

内存分析:afterBlock代码块内引用weakSelf,在dismiss后由于没有强指针指向_block,_block销毁,所以在afterBlock外部用强指针,指向_block;完整内存分析图如下:
block变量的传递

注意点:

  1. 如果block访问外部局部变量没有被任何关键字修饰,都是值传递
  2. block访问外部变量被__block,static修饰,指针传递
  3. 访问的全部变量,也是指针传递
    __block int a = 0;
    void(^block)() = ^{
    NSLog(@"%d",a);
    }; a = 5; block();输出结果为5
    p.s.__block修饰的变量在block内部使用时,block不会只对变量作只读拷贝操作,变量会存储到block结构中去
block开发使用场景(参数使用)

什么时候使用block充当参数传递?思想:封装一个功能,这个功能做什么事情有外部决定,但是什么时候调用由内部决定,这个时候就需要把block充当参数去使用

相关文章

  • 快速理解Block

    调用block 调用block方式block名称(参数) 注意点:1、声明block属性时,不同于其他数据类型+变...

  • Block原理探究(上篇)-Block本质及存储域问题

    主要内容:1.理解Block的本质2.理解Block的存储域分类3.理解Block的Copy原理 一、探究Bloc...

  • iOS Block完全使用指南

    1、Block的声明 格式: 举例: 2、Block的定义 格式: 举例: Tips:快速生成Block定义:在方...

  • block用法大全

    block语句块 如何解决block循环引用 高逼格理解block循环引用 block相关

  • 理解Block

    一、block其实是有类型的, 且一共有3种类型, 全局块, 栈块, 堆块: 1.__NSGlobalBlock_...

  • 理解Block

    堆栈的区别:经典解释 原作者不详,未详细查询,从其它地方转载并修改部分叙述,特此说明 预备知识:程序的内存分配一个...

  • 理解Block

    概念 Block是Cocoa和Cocoa框架的匿名函数的实现,所谓匿名函数,就是一段具有对象性质的代码段,一方面这...

  • 理解Block

    title: 理解Block block是开发中经常用到的一个对象,或者说一个方法。在很多编程语言中,都有闭包的概...

  • Block理解

    1: 什么是block?1.0: Block的语法1.1: block编译转换结构1.2: block实际结构 2...

  • block理解

    1 block基本概念 block作用:保存一段代码 block声明:void(^block)(void) blo...

网友评论

    本文标题:快速理解Block

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