1. Block内存布局基础解析在Objective-C和Swift开发中Block是一个非常重要的概念。它本质上是一个匿名函数可以捕获上下文中的变量。理解Block的内存布局对于深入掌握iOS/macOS开发至关重要特别是在处理内存管理、性能优化和调试复杂问题时。Block在内存中的结构可以抽象为以下C结构体struct Block { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct Block_descriptor *descriptor; // 捕获的变量... };这个结构体中的每个字段都有其特定的作用isa指针表明Block也是一个Objective-C对象flags存储了Block的各种特性标志reserved是保留字段invoke是指向实际执行代码的函数指针descriptor包含了Block的元信息最后是Block捕获的各种变量在实际开发中我们经常会遇到三种类型的Block__NSStackBlock__创建在栈上的Block__NSMallocBlock__创建在堆上的Block__NSGlobalBlock__全局的Block注意在ARC环境下编译器会自动将StackBlock进行retain操作使其变为MallocBlock。这是很多开发者容易忽略的一个细节。2. Block结构体字段深度剖析2.1 isa指针与Block类型Block的isa指针指向它的类对象这决定了Block的类型和行为。我们可以通过lldb调试器查看Block的类型(lldb) po $x0 __NSStackBlock__: 0x16ba0f280isa指针的取值有以下几种可能__NSStackBlock__表示这是一个栈上的Block__NSMallocBlock__表示这是一个堆上的Block__NSGlobalBlock__表示这是一个全局的Block在ARC环境下编译器会自动对StackBlock进行retain操作使其变为MallocBlock。这也是为什么在ARC下我们很少看到StackBlock的原因。2.2 flags字段详解flags字段包含了Block的各种特性标志这些标志定义在LLVM源码的CGBlocks.h中enum BlockLiteralFlags { BLOCK_IS_NOESCAPE (1 23), BLOCK_HAS_COPY_DISPOSE (1 25), BLOCK_HAS_CXX_OBJ (1 26), BLOCK_IS_GLOBAL (1 28), BLOCK_USE_STRET (1 29), BLOCK_HAS_SIGNATURE (1 30), BLOCK_HAS_EXTENDED_LAYOUT (1u 31) };值得注意的是flags的低16位实际上存储了Block的引用计数retainCountblock_retain_count flags 0xffff;2.3 invoke函数指针invoke指针指向Block实际要执行的代码。这里有一个重要的细节Block函数接收的第一个参数总是Block对象本身。这意味着Block函数实际上是这样的void block_function(struct Block *self, int arg1, int arg2) { // 函数体 }我们可以通过lldb查看invoke指针指向的函数(lldb) image lookup -a 0x00000001043eff4c Address: iOSTest[0x0000000100003f4c] (iOSTest.__TEXT.__text 12020) Summary: iOSTest__22-[BlockHandler handle]_block_invoke at BlockHandler.m:163. Block Descriptor深入解析Block Descriptor包含了Block的元信息它的结构如下struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy_helper)(void *dst, void *src); void (*dispose_helper)(void *src); };编译器会为每个Block生成一个独特的描述符名称例如__block_descriptor_40_e8_32s_e14_v20?0i8i12i16l这个名称的各个部分都有特定含义40Block占用的字节数十进制e8表示支持异常对齐字节数为832s捕获的变量在Block结构体中的偏移量是32类型是强引用对象e14签名字符串的长度是14v20?0i8i12i16Block的签名信息提示只有当Block的标志设置了BLOCK_HAS_COPY_DISPOSE时描述符中才会有copy_helper和dispose_helper函数。4. Block变量捕获机制4.1 变量捕获规则Block对变量的捕获遵循以下规则全局变量和静态变量不会被捕获自动变量auto会被捕获如果内层Block捕获了一个变量那么所有外层Block也会捕获这个变量例如下面的代码int i 3; void(^outer)(void) ^{ void(^inner)(void) ^{ NSLog(%d, i); }; };即使outer Block没有直接使用变量i它也会捕获i因为inner Block使用了i。4.2 不同类型的变量捕获Block对不同类型变量的处理方式也不同基本数据类型直接捕获值Objective-C对象在MRC下需要手动管理内存在ARC下会自动处理会设置BLOCK_HAS_COPY_DISPOSE标志Block变量会设置BLOCK_HAS_COPY_DISPOSE标志C对象会设置BLOCK_HAS_CXX_OBJ标志同时也会设置BLOCK_HAS_COPY_DISPOSE标志4.3 __block修饰符使用__block修饰的变量会被特殊处理变量会被包装成一个结构体允许在Block内部修改该变量会影响变量的存储位置和生命周期5. Block内存管理实践5.1 Block的拷贝行为Block的拷贝行为取决于它的类型GlobalBlockcopy操作直接返回自身StackBlockcopy会将其复制到堆上变成MallocBlockMallocBlockcopy会增加引用计数在ARC环境下编译器会自动插入适当的copy/release调用。但在MRC下开发者需要手动管理Block的内存。5.2 循环引用问题Block容易导致循环引用特别是在捕获self时// 危险的写法 self.block ^{ [self doSomething]; };解决方法包括使用weak-strong dance在适当的时候手动置nil使用weakify/strongify宏如果使用ReactiveCocoa5.3 性能优化建议避免在循环中创建Block对于不会逃逸的Block可以使用__attribute__((noescape))修饰尽量减少Block捕获的变量数量对于频繁执行的Block考虑缓存起来重复使用6. 实际调试技巧6.1 使用lldb检查Block我们可以使用lldb来检查Block的内存布局# 查看Block的类型 (lldb) po [block description] # 查看Block的内存内容 (lldb) x/8g block_address # 查看invoke指针指向的函数 (lldb) image lookup -a invoke_address # 查看descriptor的内容 (lldb) x/8g descriptor_address6.2 常见问题排查EXC_BAD_ACCESS可能是StackBlock被释放后继续使用检查Block是否被正确复制到堆上内存泄漏检查是否有循环引用使用Instruments的Leaks工具检测性能问题检查是否有不必要的Block拷贝使用Time Profiler分析Block创建和执行的耗时7. Block的高级应用7.1 作为API设计元素Block非常适合用于异步回调集合操作动画完成处理自定义控制流例如[UIView animateWithDuration:0.3 animations:^{ // 动画代码 } completion:^(BOOL finished) { // 完成处理 }];7.2 与GCD的结合使用Block是GCD的天然搭档dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 后台任务 dispatch_async(dispatch_get_main_queue(), ^{ // 主线程更新UI }); });7.3 自定义Block-based API设计良好的Block-based API应该明确命名如completionHandler、progressBlock等提供所有必要的参数考虑错误处理文档说明Block的执行线程和内存管理语义例如- (void)fetchDataWithCompletion:(void (^)(NSData *data, NSError *error))completion;理解Block的内存布局对于iOS/macOS开发者来说是一项基础但至关重要的技能。它不仅帮助我们编写更高效的代码还能在出现问题时快速定位和解决。在实际项目中我经常使用lldb来检查Block的内存布局这帮助我解决了许多棘手的内存问题。记住Block虽然强大但也需要谨慎使用特别是在内存管理方面。
企业数字化 ERP 产品动态
相关推荐
Xcode Flappy Bird 复刻工程:从零搭建到二次开发 简介:这份资源是面向 iOS 游戏开发初学者与进阶者的 Flappy Bird 复刻工程源码,基于 Xcode 环境构建,围绕 2D 休闲游戏的核心玩法展开,可用于学习物理模拟、触摸交互与得分判定等完整开发流程。压缩包共 58 个文件,约 … · 2026/11/9 22:03:17
视觉注意力机制在冷启动推荐系统中的应用与优化 1. 项目背景与核心价值视觉注意力引导冷启动这个课题,本质上解决的是新上线视觉系统在初始阶段缺乏有效用户行为数据时的性能优化问题。想象一下,当你打开一个全新的电商APP,首页推荐的商品可能完全不符合你的口味——这正是冷启动问题的典型… · 2026/11/8 19:35:44
28元年费实现高精度会议纪要:手机+国产软件的黄金组合 1. 项目概述:从踩坑到性价比之选的会议纪要方案三年前我刚接手部门会议管理工作时,每个月要花近40小时整理会议纪要。试过市面上几乎所有高端方案——从2000元的智能录音笔到按分钟计费的AI转录服务,甚至专门配置了双屏办公设备。直到去年偶然… · 2026/11/9 4:36:49
低压电工证复核考题实操考试考什么 低压电工证复核多少钱 低压电工证复核考题实操考试考什么 低压电工证复核多少钱 工地太忙根本没时间复习考试,尤其是像低压电工这样的特种作业岗位,每天穿梭在钢筋水泥之间,哪还有精力去记那些复杂的电路图?更别提还要面对低压电工证复核考题了,一不留神,证书就过期了,还得… · 2026/11/10 18:04:01
布线用电工证吗良心建议:证书过期了不知道怎么复审延期怎么办? 布线用电工证吗良心建议:证书过期了不知道怎么复审延期怎么办? 证书过期了不知道怎么复审延期?别急,这可能是你遇到的第一个坑,但不是最后一个。特种作业操作证是从事相关工作的“通行证”,一旦过期,不仅影响日常工作,还可能面临法律风险。尤其是低压… · 2026/11/10 18:04:01
惠州市电工证复核要过吗?电子证书影响你找工作机会 惠州市电工证复核要过吗?电子证书影响你找工作机会 现在找工作, 特种作业证是硬门槛 ,尤其在施工、建筑、电力等岗位, 没有电工证,连面试资格都没有 。你可能已经拿到了电工证,但别忘了, 惠州市电工证复核… · 2026/11/10 18:04:01
电工证每月几号开考 2026河南最新政策怎么安排考试时间 电工证每月几号开考 2026河南最新政策怎么安排考试时间 实操考试心里没底怕挂科,这是很多正在准备电工证考试的朋友最真实的感受。尤其在2026年河南最新政策下,考试时间安排、流程变化、备考方式都和以前不一样了。南阳卧龙区不少劳务班组负责人也… · 2026/11/10 18:04:01
各省建筑电工证过期了怎么办?电子证书复审全攻略 各省建筑电工证过期了怎么办?电子证书复审全攻略 证书过期了不知道怎么复审延期,这事儿在郑州很多中小型施工企业负责人身上都发生过。特别是现在国家对特种作业人员管理越来越严格,建筑电工证一旦过期,不仅影响项目开工,还可能面临行政处罚,甚至被列入… · 2026/11/10 18:03:01
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/10 2:16:10
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/10 17:46:39
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/10 17:11:43
丹寨电工证怎么考?内部消息透露报考条件和流程 丹寨电工证怎么考?内部消息透露报考条件和流程 急需特种作业证才能上岗找工作,这是很多电工朋友最真实的焦虑。尤其是像丹寨电工证这样的证书,直接影响你的职业发展和薪资待遇。但你知道吗?很多人都在报考过程中踩坑,有的甚至花了几千块最后白忙一场。今… · 2026/11/10 0:00:13
成都建筑电工证办理郑州报考避坑指南 成都建筑电工证办理郑州报考避坑指南 证书过期了不知道怎么复审延期?别慌!这篇文章手把手带你解决成都建筑电工证办理的难题,顺便避掉郑州报考的那些坑。不管你是刚拿到证的新手,还是准备复审的老电工,这波干货都别错过。… · 2026/11/10 0:00:13
梅州低压电工证怎么考?怕被中介坑?手把手教你全国通用流程 梅州低压电工证怎么考?怕被中介坑?手把手教你全国通用流程 你是不是正为梅州低压电工证发愁?不知道去哪报名,怕被中介骗钱,又担心证书是不是全国通用?其实,这些顾虑都是正常人会有的。今天我就从一个在开封房建工程一线干了几年的电工角度,手把手教你… · 2026/11/10 0:00:13
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:23:35
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/9 11:23:58
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/10 17:00:47