iOS

iOS底层探索之Block(一)——初识Block(你知道几种B

2021-08-30  本文已影响0人  俊而不逊

说在前面

Block你知道几种?Block的循环引用你有几种解决办法呢?

在上一篇博客结束了多线程锁篇章的内容,最后也带大家手写了读写锁,那么从现在开始,将开启Block的探索篇章!

Block.png

1. 什么是 Block?

Block就是一个代码块, Block是将函数及其执行上下文封装起来的对象,是一个匿名的函数对象, Block也有isa。既然Block内部封装了函数,那么它同样也有参数和返回值,本身也可以被作为参数在方法和函数间传递。具体的内容,后续的博客中会重点分析,这里就先不展开了!

2. 你知道几种 block?

2.1 NSGlobalBlock

先来看看第一种Block,代码如下,猜猜打印结果是什么?

 void (^jpBlock)(void) = ^{
    };
    NSLog(@"%@",jpBlock);
NSGlobalBlock
从代码上来看,这是一个无参数也无返回值的BlockBlock体内什么也没有做,也没有引用任何的变量,总结来说如下:

GlobalBlock

2.2 NSMallocBlock

看看如下这个代码,打印是什么Block

int a = 10;

void (^jpBlock)(void) = ^{
   NSLog(@"输出:%d",a);
};
NSLog(@"%@",jpBlock);
NSMallocBlock
这里引用了一个外部的变量,打印是NSMallocBlock,也就是堆Block

NSMallocBlock

Block内部使用局部变量或者OC属性,并且赋值给强引用或者Copy修饰的变量。

2.3 NSStackBlock

NSStackBlock:

    int a = 10;

    void (^__weak jpBlock)(void) = ^{
         NSLog(@"输出:%d",a);
    };
    NSLog(@"%@",jpBlock);
NSStackBlock

ARC环境下,使用_ _weak修饰就是一个栈Block,如上图代码所示,打印结果也可以验证是栈Block

既然三种Block都已经介绍完了,那么接下来举几个面试题看看。

3. Block面试题举例

3.1 例子 1

block 捕获外部变量——对外部变量的引用计数处理

代码如下:

 NSObject *objc = [NSObject new];
    NSLog(@"%ld",CFGetRetainCount((__bridge CFTypeRef)(objc))); // 1

    void(^strongBlock)(void) = ^{
        NSLog(@"---%ld",CFGetRetainCount((__bridge CFTypeRef)(objc)));
    };
    strongBlock();

    void(^__weak weakBlock)(void) = ^{
        NSLog(@"---%ld",CFGetRetainCount((__bridge CFTypeRef)(objc)));
    };
    weakBlock();
    
    void(^mallocBlock)(void) = [weakBlock copy];
    mallocBlock();
    
打印结果
第一个打印1都是很好理解,就是后面的打印有点懵,那么解答如下:

3.2 例子 2

block堆栈释放差异举例,猜猜是否可以正常打印?

代码如下:

#pragma mark - block 堆栈释放差异
- (void)jpreno {
    
    int reno = 10;
    void(^__weak weakBlock)(void) = nil;
    {
        // 栈区
        void(^__weak strongBlock)(void) = ^{
            NSLog(@"jp1:---%d", reno);
        };
        weakBlock = strongBlock;
        NSLog(@"jp2:--%@--%@",weakBlock,strongBlock);
    }
    weakBlock();

}

这里估计很多人会有疑惑,这种赋值还是第一次见,但是面试的使用肯定会遇到各种奇奇怪怪的题目的,这里讲解了,以后就不怕了😁。

那么把代码改一下,看看结果如何呢???

代码改后运行崩溃了

代码改后运行崩溃了,什么鬼啊?哪里改了啊?我怎么没有发现哪里改动了呢!这里把strongBlock__weak给去掉了就变成了NSMallocBlock

那么该如何解决这个问题呢?请看下面的代码

解决崩溃
上面的例子崩溃了,是因为堆区的 block出了作用域,被释放了,那么现在把两个block__weak都去掉,则能够正常运行并打印结果

因为此时的赋值,weakBlock对堆中的block进行了强引用,代码块运行结束后不会释放掉,也就不存在野指针的问题了。

4.总结

下篇预告:

那强引用释放不掉,出现循环引用,该怎么解决呢?下一篇将针对 block的循环引用,做出分析和解决办法!

更多内容持续更新

🌹 喜欢就点个赞吧👍🌹

🌹 觉得有收获的,可以来一波,收藏+关注,评论 + 转发,以免你下次找不到我😁🌹

🌹欢迎大家留言交流,批评指正,互相学习😁,提升自我🌹

上一篇 下一篇

猜你喜欢

热点阅读