美文网首页
iOS block之三种block

iOS block之三种block

作者: luonaerduo | 来源:发表于2019-08-05 14:52 被阅读0次

前言
先说明一下,因为ARC下系统会对block做一些拷贝和释放操作,对深入于理解block无益,所以本篇文章所提到的栗子编译环境均为MRC。

首先引用《Objective-C高级编程》Blocks章节中的第一句话:Blocks是对C语言的扩充功能。而且OC是建立在C语言基础上之上,添加了面向对象机制的一门编程语言。

所以不要再说block的实现原理是C++的函数指针了,正确答案是:block的实现原理是C语言的函数指针。
函数指针即函数在内存中的地址,通过这个地址可以达到调用函数的目的。

Block是NSObject的子类,拥有NSObject的所有属性,所以block对象也有自己的生命周期,生存期间也会被持有和释放。

block有三种:
NSGlobalBlock 静态区(全局区)block,这是一种特殊的bloclk,因为不引用外部变量而存在。另外,作为静态区的对象,它的释放是有操作系统控制的,这一点我们最后再聊。
NSStackBlock 栈区block,位于内存的栈区,一般作为函数的参数出现。
NSMallocBlock 堆区block,位于内存的堆区,一般作为对象的property出现。

如果一个blcok引用了外部变量是栈block,则其不引用外部变量就成为了静态blcok。
如果一个block引用了外部变量是堆block,则其不引用外部变量就成为了静态block。

NSStackBlock 栈区block
说到栈操作,大家都明白,出栈和入栈,函数只有入栈后才能执行,出栈后就释放了。
栈block一般在函数内部定义,并在函数内部调用;或者在函数外部定义,作为函数的一个参数在函数内部调用。函数出栈时和其他变量或参数一起释放。

栈区block形式有2,如下:

栈区block形式1

  • (void)xxx
    {
    __block int i = 0;
    void (^block1)() = ^{
    //此处若不引用外部变量i,则block1是静态block,若引用,则为栈block
    i++;
    NSLog(@"i = %d",i);
    };

    block1();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    栈区block形式2:

  • (void)saveFile:(NSDictionary *)dic complete:(void(^)(BOOL success))complete
    {
    //dic写入本地近作demo使用,实际开发要判断路径是否存在,以及dic中是否存在null值等
    NSString * path = [NSHomeDirectory() stringByAppendingFormat:@"/Caches/dicInfo"];
    BOOL suc = [dic writeToFile:path atomically:YES];

    if (complete) {
    //若complete中不引用外部变量suc,则complete是静态block,此处complete为栈block
    complete (suc);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    NSMallocBlock 堆区block
    堆区是内存的常驻区域,也叫永久存储区,block一般在函数中定义,最多是个栈block,什么时候才能打怪升级成为堆block呢?
    在MRC时代你需要使用Block_copy()方法,才可以将blcok复制到堆中。

然而复制到堆中有何用处呢?
首先,作为一个对象,把它复制到堆中,想要使用它肯定要有一个指针指向它,而指向它的指针是作为property或静态变量出现的(如果不被引用也就没有了常驻于堆区的意义),而实际开发中多使用property引用。

在MRC中,如果一个类的block属性是使用copy修饰的,则不需要手动调用Block_copy将其复制到堆中。如果是用strong修饰的,则必须使用Block_copy()将其复制到堆中,并在释放时调用Block_release()方法将其释放,否则会因野指针导致程序崩溃。

@interface TestV : UIView

@property (nonatomic, strong) void(^block1)();
@property (nonatomic, copy) void(^block2)();

@end
1
2
3
4
5
6

  • (void)testFunc
    {
    __block int i = 0;

    void (^block1)() = ^{
    //此处若不引用外部变量i,则block1是静态block,若引用,则为堆block
    i++;
    NSLog(@"block1 -- i = %d",i);
    };
    void (^block2)() = ^{
    i --;
    NSLog(@"block2 -- i = %d",i);
    };

    TestV * view = [[TestV alloc] initWithFrame:CGRectMake(100, 100, kScreenWidth - 200, 40)];
    [self.view addSubview:view];

    view.block1 = Block_copy(block1);
    view.block2 = block2;

    NSLog(@"block1 -- %@",block1);
    NSLog(@"block2 -- %@",block2);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    因此在MRC中,基本上会用copy关键字修饰block,既优雅又省代码,还避免了因为未调用Block_release而造成内存泄露,这大概是很多人在ARC项目中依旧使用copy修饰block的历史原因。

其实在ARC下使用strong或copy修饰block没啥区别,亲测有效,可能会遇到一些开发人员,他们看到ARC工程中出现strong修饰的block就会提出质疑,那只能说明他们没有亲自写两行代码测试过是否真的有区别。

NSGlobalBlock 静态block
既然存在于静态区,则只有当进程被杀死,进程所占用的内存空间被释放后,静态区的对象才会被释放。静态block并不依附于某个对象而存在,也并不为某个类对象单独享有,而是所有的该类对象都共同拥有这个block,都有这个block的使用权,不管有多少个类对象,在程序运行期间这个block始终只有一份,直到进程被杀死,内存被释放。

以下代码片段将有助于你的理解:

//在一个成员方法中定义一个静态block,然后打印出self的地址和block的地址

  • (void)blockAction
    {
    void(^block1)() = ^{
    //未引用外部变量,则为静态block
    NSLog(@"block1");
    };

    NSLog(@" -- self : %p",self);
    NSLog(@" -- %@ --",block1);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //初始化了两个对象,同时调用各自的成员方法
    [_v1 blockAction];
    [_v2 blockAction];
    1
    2
    3
    //打印结果如下:两个对象地址不同,两个block地址相同
    xxx BlockDemo[22106:1969807] -- self : 0x7f81da513f20
    xxx BlockDemo[22106:1969807] -- <NSGlobalBlock: 0x1057ca1a0> --
    xxx BlockDemo[22106:1969807] -- self : 0x7f81da512770
    xxx BlockDemo[22106:1969807] -- <NSGlobalBlock: 0x1057ca1a0> --


作者:future
来源:CSDN
原文:https://blog.csdn.net/Mo_Mo123/article/details/77923634
版权声明:本文为博主原创文章,转载请附上博文链接!

相关文章

  • iOS block之三种block

    前言先说明一下,因为ARC下系统会对block做一些拷贝和释放操作,对深入于理解block无益,所以本篇文章所提到...

  • iOS-2 Block

    block块 系列文章: iOS Block浅浅析 - 简书 iOS Block实现原理 iOS Block __...

  • iOS Block存储域及循环引用

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block __block说明符...

  • iOS Block实现原理

    系列文章:iOS Block概念、语法及基本使用iOS Block __block说明符iOS Block存储域及...

  • block系列文章总结

    iOS源码解析:Block的本质<一>iOS源码解析:Block的本质<二>Objective C block背后...

  • iOS Block __block说明符

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block存储域及循环引用 上一...

  • iOS复习之Block

    iOS面试中如何优雅回答Block iOS block循环引用

  • Block 初见

    Block 初见 介绍 iOS block 的相关知识 目录 Block 背景知识 Block 使用方式 Bloc...

  • iOS Block概念、语法及基本使用

    系列文章:iOS Block实现原理iOS Block __block说明符 最近又翻了一遍《Objective-...

  • ios相关:block

    三种常用方式 用block改写UIButton点击事件,block改写UIAlerView的代理 iOS bloc...

网友评论

      本文标题:iOS block之三种block

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