美文网首页将来跳槽用
iOS相关知识(六)-- block

iOS相关知识(六)-- block

作者: 奋斗的小马达 | 来源:发表于2021-09-23 16:27 被阅读0次

1、block的本质

block本质上也是一个OC对象,它内部也有个isa指针
block是封装了函数调用以及函数调用环境的OC对象

2、block的变量捕获(capture)

为了保证block内部能够正常访问外部的变量,block有个变量捕获机制


block的变量捕捉.png

结论:

局部变量(block内部会捕捉变量)

1、auto 
使用auto修饰的局部变量,变量的作用域就在局部 离开作用域就会被销毁
 block内部 捕捉auto修饰的局部变量 在block创建的时候直接把值给传递进去了


2、static
使用auto修饰的局部变量,只要程序没有退出就一直存在在内存中不被销毁
 block内部 捕捉static 修饰的局部变量 在block创建的时候直接把地址给传递进去了
全局变量 (block内部不会捕捉变量)
直接访问全局变量的值,不会捕获变量
也就是说 block 内部访问局部变量时 block在创建的时候就会在内部自动生成对应的变量 然后将值或指针传递进去
Block 内部访问全局变量的时候 不会做任何处理 直接访问全局变量的值

原因是:在垮函数调用block的时候 局部变量随时可能会被销毁  所以为了保证block内部访问的值不被销毁,block在创建的时候就直接自动生成对应的变量来存储内部访问的变量。全局变量无论什么地方访问他都会存在 所以不用关心被销毁因此block内部不会去捕捉

3、block的类型

block有3种类型,可以通过调用class方法或者isa指针查看具体类型,
最终都是继承自NSBlock类型(NSBlock 继承 NSObject)
__NSGlobalBlock__ ( _NSConcreteGlobalBlock )
__NSStackBlock__ ( _NSConcreteStackBlock )
__NSMallocBlock__ ( _NSConcreteMallocBlock )

三种block 内存分配

三种block 内存分配.png

上图注解:

上图 从上至下内存地址排列 是 从低地址到高地址

程序区域:平时写的OC代码 都在 程序区域也就是.text区

数据区域:一般全局变量都放在数据区域也就是.data区

堆:平时alloc 出来的对象都会放在 堆区
(堆区:动态分配内存,也就是开发者自己去申请内存,且开发者自己管理内存)

栈:存放局部变量,程序会自己管理内存


如何区分这三种block

区分这三种block.png

上图注解:

globalBlock

没有访问auto变量的block 都是 globalBlock
如:
     void (^block1)(void) = ^{
            NSLog(@"Hello");
        };
或:
//a 是局部变量
       static int a = 10;
        void (^block1)(void) = ^{
            NSLog(@"Hello----%d",a);
        };

或:
//a 是全局部变量
       int a = 10;
        void (^block1)(void) = ^{
            NSLog(@"Hello----%d",a);
        };

只记住一点:只要没有访问auto变量的block 都是globalBlock

stackBlock

如果访问了 auto变量 就是 stackBlock

在ARC环境下,程序在运行的时候会自动对stackBlock进行copy处理 所以在ARC环境下打印出来的block类型就是 mallocBlock

原因:stackBlock 是在栈区,栈区会自动销毁内存,如果垮函数去调用block
此时block可能已经被释放了 如果再去调用这个block 可能访问的就是一块垃圾内存,

为了解决这个问题,

mallocBlock

stackBlock 调用copy 就会变成mallocBlock 
在ARC环境下,程序在运行的时候会自动对stackBlock进行copy处理

在开发过程中我们使用的block一般都是 mallocBlock

每一种类型的block调用copy后的结果如下所示

block调用copy后的结果.png

4、block的copy

在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况
block作为函数返回值时
将block赋值给__strong指针时
block作为Cocoa API中方法名含有usingBlock的方法参数时
block作为GCD API的方法参数时

5、__block修饰符

__block可以用于解决block内部无法修改auto变量值的问题

__block不能修饰全局变量、静态变量(static)

编译器会将__block变量包装成一个对象(如下图最后一张)

使用__block修饰的变量底层代码结构图.png

图解:

编译器在编译的时候会讲__block变量包装成一个对象

block内部会有一个指针  __Block_byref_age_0 *age
(如:第二个图)指向生成的对象(底层为一个结构体如最后一个图:__block变量生成的对象底层代码)

__block变量生成的对象 里面又有一个指针存放age的值(第三个图中 val)
同时内部又有一个指针指向他自己(第三个图 __forwarding)

修改方式

先看底层C++代码


block底层c++代码.png

图解:

修改age值的步骤:
1、先通过block内部的 __Block_byref_age_0 *age指针找到
__block变量生成对象(底层为结构体)的__forwarding指针(这个指针就是指向他自己)。

2、然后在结构体中找这个age。

3、最后再对其进行赋值操作。

block内部如何修改变量的值

这个问题一般问的是修改局部变量的值,因为全局变量直接可以访问到,不存在修改不了的情况


如何修改局部变量的值:
第一种:直接使用 static修饰
第二种:局部变量改为全局变量
第三种:使用__block修饰变量

最好的方式就是第三种,使用__block修饰变量  因为前两种 都是将变量永久存放在内存中。

注意:只要不对变量/对象 的值进行修改 就不要去使用__block

如下面的代码就不需要使用__block 因为他们只是使用了变量/对象而没有对其进行修改

#import <Foundation/Foundation.h>

typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
    //第一种:
       int age = 10;
        Block block1 = ^{
            NSLog(@"age is %d", age);
        };
        block1();

        
    //第二种
        NSMutableArray *arr = [[NSMutableArray alloc]init];
        Block block2 = ^{
            [arr addObject:@"444"];
            [arr addObject:@"555"];
            [arr addObject:@"666"];
            NSLog(@"arr is %@", arr);
        };
        block2();
        
    }
    return 0;
}

6、block循环引用

有三种方式:__weak 、  __unsafe_unretained 和 __block

区别:
__weak:不会产生强引用,指向的对象销毁时,会自动让指针置为nil

 __unsafe_unretained:不会产生强引用,不安全,
指向的对象销毁时,指针存储的地址值不变

所以:经常使用__weak来解决循环引用问题
使用__block解决block内部循环引用问题.png

相关文章

  • Block 初见

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

  • iOS相关知识(六)-- block

    1、block的本质 2、block的变量捕获(capture) 为了保证block内部能够正常访问外部的变量,b...

  • ios -- block相关知识

    所有的Block里面的self必须要weak一下? 很显然答案不都是,有些情况下是可以直接使用self的,比如调用...

  • 21·iOS 面试题·__block 在 ARC 和 MRC 下

    前言 对于 Block 以及 __block 相关的知识点,之前的面试题已经涉及过:04·iOS 面试题·Bloc...

  • iOS笔记--Block相关知识

    Block介绍(一)基础Block介绍(二)内存管理与其他特性block介绍(三)揭开神秘面纱(上)block介绍...

  • iOS Block 相关知识点

    1.block是什么 block就是将函数执行上下文封装起来的对象 2.block有哪些类型 全局block:不访...

  • Block相关知识

    一、Block本质 1.1、概念 Block是将函数及其执行上下文封装起来的对象。 问题1:什么是Block? B...

  • Block 相关知识

    1、什么是block 2、block截获对象 3、在什么情况下需要使用__block修饰符? 4、为什么block...

  • iOS Block 相关

    1.深入研究Block用weakSelf、strongSelf、@weakify、@strongify解决循环引用...

  • ios相关:block

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

网友评论

    本文标题:iOS相关知识(六)-- block

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