__block的深入研究

news2024/10/6 14:33:30
  • __block可以用于解决block内部无法修改auto变量值的问题

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

    • 编译器会将__block变量包装成一个对象

调用的是,从__Block_byref_a_0的指针找到 a所在的内存,然后修改值
Pasted image 20230726145216.png

第一层拷贝(block)

block中的第一层拷贝其实已经讲过了——_Block_copy将block从栈拷贝到堆

第二层拷贝(捕获变量的内存空间)

Pasted image 20230725201046.png

在函数声明时会传__main_block_desc_0_DATA结构体,在里面又会去调用__main_block_copy_0函数,__main_block_copy_0里面会调用_Block_object_assign——这就是第二层拷贝的调用入口。
根据flags & BLOCK_ALL_COPY_DISPOSE_FLAGS进到不同分支来处理捕获到的变量
Pasted image 20230726154645.png

此时捕获到的变量是被__block修饰的BLOCK_FIELD_IS_BYREF类型,就会调用*dest = _Block_byref_copy(object);

static struct Block_byref *_Block_byref_copy(const void *arg) {
    // 临时变量的保存
    struct Block_byref *src = (struct Block_byref *)arg;

    if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
        // src points to stack
        // 用原目标的大小在堆区生成一个Block_byref
        struct Block_byref *copy = (struct Block_byref *)malloc(src->size);
        copy->isa = NULL;
        // byref value 4 is logical refcount of 2: one for caller, one for stack
        copy->flags = src->flags | BLOCK_BYREF_NEEDS_FREE | 4;
        
        // 原来的区域和新的区域都指向同一个对象,使得block具备了修改能力
        copy->forwarding = copy; // patch heap copy to point to itself
        src->forwarding = copy;  // patch stack to point to heap copy
        copy->size = src->size;

        if (src->flags & BLOCK_BYREF_HAS_COPY_DISPOSE) {
            // Trust copy helper to copy everything of interest
            // If more than one field shows up in a byref block this is wrong XXX
            struct Block_byref_2 *src2 = (struct Block_byref_2 *)(src+1);
            struct Block_byref_2 *copy2 = (struct Block_byref_2 *)(copy+1);
            copy2->byref_keep = src2->byref_keep;
            copy2->byref_destroy = src2->byref_destroy;

            if (src->flags & BLOCK_BYREF_LAYOUT_EXTENDED) {
                struct Block_byref_3 *src3 = (struct Block_byref_3 *)(src2+1);
                struct Block_byref_3 *copy3 = (struct Block_byref_3*)(copy2+1);
                copy3->layout = src3->layout;
            }
            // 第三层拷贝
            (*src2->byref_keep)(copy, src);
        }
        else {
            // Bitwise copy.
            // This copy includes Block_byref_3, if any.
            memmove(copy+1, src+1, src->size - sizeof(*src));
        }
    }
    // already copied to heap
    else if ((src->forwarding->flags & BLOCK_BYREF_NEEDS_FREE) == BLOCK_BYREF_NEEDS_FREE) {
        latching_incr_int(&src->forwarding->flags);
    }
    
    return src->forwarding;
}

用原目标name的大小在堆区生成一个Block_byref
copy->forwarding = copy; & src->forwarding = copy;——原来的区域和新的区域都指向同一个对象,使得block具备了修改能力
(* src2->byref_keep)(copy, src)开始第三层拷贝

第三层拷贝(拷贝对象)

(*src2->byref_keep)(copy, src)点进去会来到Block_byref结构来,而byref_keepBlock_byref的第5个属性

struct Block_byref {
    void * __ptrauth_objc_isa_pointer isa;
    struct Block_byref *forwarding;
    volatile int32_t flags; // contains ref count
    uint32_t size;
};

struct Block_byref_2 {
    // requires BLOCK_BYREF_HAS_COPY_DISPOSE
    BlockByrefKeepFunction byref_keep;
    BlockByrefDestroyFunction byref_destroy;
};

struct Block_byref_3 {
    // requires BLOCK_BYREF_LAYOUT_EXTENDED
    const char *layout;
};

Pasted image 20230726154841.png

第5位就等于byref_keep,所以在第二层拷贝时会调用__Block_byref_id_object_copy_131

static void __Block_byref_id_object_copy_131(void *dst, void *src) {
 _Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
 _Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}

这个(char*)dst + 40看到__Block_byref_name_0就顿悟了,刚好取得变量name对象。

struct __Block_byref_name_0 {
  void *__isa;
__Block_byref_name_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 NSString *name;
};

_Block_object_assign在对BLOCK_FIELD_IS_OBJECT情况时会做出如下操作:

	case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
    case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
        /*******
         // copy the actual field held in the __block container
         // Note this is MRC unretained __block only. 
         // ARC retained __block is handled by the copy helper directly.
         __block id object;
         __block void (^object)(void);
         [^{ object; } copy];
         ********/

      *dest = object;
      break;

block捕获的外接变量由ARC自动管理,捕获到name进行拷贝
block中有三层拷贝:拷贝block、拷贝捕获变量的内存地址、拷贝对象

_ Block_object_dispose

void _Block_object_dispose(const void *object, const int flags) {
    switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
      case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
      case BLOCK_FIELD_IS_BYREF:
        // get rid of the __block data structure held in a Block
        _Block_byref_release(object);
        break;
      case BLOCK_FIELD_IS_BLOCK:
        _Block_release(object);
        break;
      case BLOCK_FIELD_IS_OBJECT:
        _Block_release_object(object);
        break;
      case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
      case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
      case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
      case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK  | BLOCK_FIELD_IS_WEAK:
        break;
      default:
        break;
    }
}

// API entry point to release a copied Block
void _Block_release(const void *arg) {
    struct Block_layout *aBlock = (struct Block_layout *)arg;
    if (!aBlock) return;
    if (aBlock->flags & BLOCK_IS_GLOBAL) return;
    if (! (aBlock->flags & BLOCK_NEEDS_FREE)) return;

    if (latching_decr_int_should_deallocate(&aBlock->flags)) {
        _Block_call_dispose_helper(aBlock);
        _Block_destructInstance(aBlock);
        free(aBlock);
    }
}

  • 如果是释放对象就什么也不做(自动释放)
  • 如果是__block修饰,就将指向指回原来的区域并使用free释放

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/825611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VLAN介绍

目录 VLAN的特点: VLAN的好处: VLAN的实现原理 VLAN标签 VLAN的划分方式 接口划分VLAN--接口类型 Access接口 Trunk接口 Hybrid接口 实现VLAN之间通信 使用路由器物理接口 使用子接口 使用三层交换机的VLANIF接口 配置 VLANIF的转发流程 三层交换机参与下的三层…

【图解】Mask R-CNN 架构

Mask R-CNN 是一种自顶向下(top-down)的姿态估计模型,它是在 Faster R-CNN [44] 这个目标检测框架的基础上扩展而来的。目标检测是指从图像中检测出不同类别的物体,并且输出它们的边界框(bounding box)。 …

exp/imp选项说明

1、exp选项 2、imp选项 3、举例 (1)、imp system/manager filetank logtank fromuser(seapark,amy) touser(seapark1, amy1);(2)、imp system/manager file(paycheck_1,paycheck_2,paycheck_3,paycheck_4) logpaycheck.log filesize1G fully;(3)、imp system/manager fileseap…

【css】解决元素浮动溢出问题

如果一个元素比包含它的元素高&#xff0c;并且它是浮动的&#xff0c;它将“溢出”到其容器之外&#xff1a;然后可以向包含元素添加 overflow: auto;&#xff0c;来解决此问题&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html> <head> <style>…

如何克服学习和工作中的焦虑和迷茫

如何克服学习和工作中的焦虑和迷茫 &#x1f607;博主简介&#xff1a;我是一名正在攻读研究生学位的人工智能专业学生&#xff0c;我可以为计算机、人工智能相关本科生和研究生提供排忧解惑的服务。如果您有任何问题或困惑&#xff0c;欢迎随时来交流哦&#xff01;&#x1f6…

落实《中国人民银行业务领域数据安全管理办法》,极盾科技是怎么做的?

“软标准”变成“硬规范”&#xff01; 近日&#xff0c;央行发布《中国人民银行业务领域数据安全管理办法》征求意见稿&#xff08;以下称《管理办法》&#xff09;&#xff0c;以部门规范性文件的方式&#xff0c;全面衔接《数据安全法》&#xff0c;细化明确中国人民银行业…

村田授权代理:共模扼流线圈针对汽车专用设备高频噪声的降噪对策

车载市场正不断扩充ADAS、自动驾驶、V2X、车载信息系统等的应用。由于此类应用要处理庞大的信息&#xff0c;因此为了执行处理&#xff0c;内部处理信号的处理速度亦不断高速化。另一方面&#xff0c;由于部件数量增多&#xff0c;安装密度增大&#xff0c;因此要求部件小型化。…

364 · 接雨水 II

链接&#xff1a;九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 题解&#xff1a; 九章算法 - 帮助更多程序员找到好工作&#xff0c;硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧

OpenAI的提供的Model简要介绍

OpenAI提供的model 通过OpenAI的接口可以查看所有支持的模型(目前的账号无GPT4的权限&#xff0c;所以没有列举GPT4相关的模型)。 import os import openai import pandas as pd from IPython.display import displayopenai.api_key os.getenv("OPENAI_API_KEY")…

记录一下点亮过的技能点

一年级 软件工程导论也就是 计算机导论&#xff0c;主要介绍计算机的发展历程概况&#xff0c;对计算机有个大体的了解。 编程语言学习 C语言&#xff0c;基础语法会用&#xff0c;其实现在忘得有点多了&#xff0c;需要多查询文档才行。 二年级 计算机组成原理&#xff0c;…

【LeetCode每日一题】——807.保持城市天际线

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 矩阵 二【题目难度】 中等 三【题目编号】 1572.矩阵对角线元素的和 四【题目描述】 给你一…

助力工业物联网,工业大数据之费用事实指标分析及实现【二十四】

文章目录 1&#xff1a;费用事实指标分析及实现2&#xff1a;差旅事实指标分析及实现3&#xff1a;网点物料事实指标分析及实现 1&#xff1a;费用事实指标分析及实现 目标&#xff1a;实现DWB层费用报销事实指标表的构建 路径 step1&#xff1a;目标需求step2&#xff1a;数据…

有砟铁路三维地质雷达检测数值模拟研究

有砟铁路三维地质雷达无损检测数值模拟研究 前言 据统计&#xff0c;全国铁路营业里程超过14.63万公里&#xff0c;其中高铁超过3.8万公里&#xff1b;全国铁路路网密度152.3公里/万平方公里。有砟铁路主要建造于2012年以前&#xff0c;截止2012年&#xff0c;全国有砟铁路达…

Baklib: 0代码的在线帮助中心

Baklib是一款0代码的在线帮助中心工具&#xff0c;旨在帮助企业和开发者快速搭建和管理自己的帮助中心。无需编写任何代码&#xff0c;只需几个简单的步骤&#xff0c;即可创建一个功能齐全、易于使用的在线帮助中心。Baklib提供了丰富的功能和灵活的定制选项&#xff0c;使用户…

关于迪文屏文本显示 字库生成

生成 30的字体 界面上显示 屏幕上文本控件的点阵数 为字库生成软件的 宽和高 30 30 字库软件的下载链接 三、汉字字库生成 百度网盘链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;1o5t https://blog.csdn.net/qq_34118600/article/details/115469371

「如何优雅有效利用周末和下班时间?」

文章目录 每日一句正能量前言下班的时间规划周末的时间规划提升周末体验感的好方法怎样才能获得充分的休息后记 每日一句正能量 眼望古城街尽&#xff0c;心谱落愁无序&#xff0c;旧时的誓言&#xff0c;曾而相似&#xff0c;河水在遵循河道的指引下&#xff0c;在曲折前进中放…

通过Python调用禅道API

禅道API接口&#xff0c;非REST接口 调试版本&#xff1a;11.3 百度出来的100%都用不了&#xff08;本篇除外...&#xff09;。于是自己修改了网上代码&#xff0c;先get session&#xff0c;再post登录&#xff0c;最后调用产品列表验证&#xff0c;实测通过。 1 import req…

SAP 物料主数据 字段 配额安排 变化

ECC版本 字段‘配额安排’在物料主数据中&#xff0c;可选使用范围 S4新版本 字段‘配额安排’已经隐藏&#xff0c;后台字段去掉了&#xff0c;屏幕字段设置了不可见&#xff0c;系统默认选择了4

流程管理软件:优化工作流程的数字化解决方案

有这么多任务需要跟踪&#xff0c;一个优秀的工作流系统对于项目经理完成他们的工作至关重要。通过使用工作流软件&#xff0c;项目经理可以避免诸如浪费时间和资源、过度风险和损害最终结果等陷阱。他们可以放心&#xff0c;他们的工作将按照正确的顺序完成&#xff0c;并在此…

文件管理:按名称批量归类,简化整理任务!

在数字化时代&#xff0c;我们每天都会面对海量的文件&#xff0c;从文档、图片、视频到音频&#xff0c;各种各样的文件都在我们的电脑中汇聚。然而&#xff0c;你是否曾为找不到需要的文件而烦恼&#xff0c;或者为整理大量文件而头疼&#xff1f;为了帮助大家解决这些问题&a…