当前位置: 首页 > news >正文

__block的深入研究

  • __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_byrefstruct 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 stackcopy->flags = src->flags | BLOCK_BYREF_NEEDS_FREE | 4;// 原来的区域和新的区域都指向同一个对象,使得block具备了修改能力copy->forwarding = copy; // patch heap copy to point to itselfsrc->forwarding = copy;  // patch stack to point to heap copycopy->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 XXXstruct 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 heapelse 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 countuint32_t size;
};struct Block_byref_2 {// requires BLOCK_BYREF_HAS_COPY_DISPOSEBlockByrefKeepFunction byref_keep;BlockByrefDestroyFunction byref_destroy;
};struct Block_byref_3 {// requires BLOCK_BYREF_LAYOUT_EXTENDEDconst 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.lryc.cn/news/105561.html

相关文章:

  • Segment anything(图片分割大模型)
  • 【雕爷学编程】MicroPython动手做(27)——物联网之掌控板小程序3
  • Java中集合容器详解:简单使用与案例分析
  • 机器学习04-数据理解之数据可视化-(基于Pima数据集)
  • 百度@全球开发者,见证中国科技超级“碗”!
  • 分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离(一)
  • Ajax跨域问题
  • Vue + FormData + axios实现图片上传功能
  • 设计模式系列:经典的单例模式
  • macbook pro 散热解决办法
  • 高并发与性能优化的神奇之旅
  • Django Rest_Framework(一)
  • VB+ACCESS智能公交考勤系统管理软件设计与实现
  • 企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图 tbms
  • 【ES】笔记-ECMAScript 相关介绍
  • FFmpeg下载安装及Windows开发环境设置
  • transformer面试常考题
  • aws的EC2云服务器
  • hive函数大全
  • k8s概念-StatefulSet
  • HTMLCollection 和 NodeList 的详解,以及两者在开发情况下差异。
  • 基于FPGA的超声波测距——UART串口输出
  • Python web实战之 Django 的 MVC 设计模式详解
  • Stable Diffusion VAE:改善图像质量的原理、选型与使用指南
  • maven里面没有plugins dependence问题解决
  • Wi-Fi 6技术详解
  • 【LeetCode】446. 等差数列划分II -- 子序列
  • 几个似非而是的注释问题
  • 【设计模式|上】创建型模式
  • 【JS】类 class