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

「OC」源码学习——alloc与init的实现

「OC」源码学习——alloc与init的实现

前言

费劲千辛万苦终于项目给写完了,进入下一个阶段,源码的学习

alloc的调用顺序

我们在main函数之中打上断点,先运行

image-20250422120724912

再在alloc之中的各个函数之中打上断点,在关键步骤上打上断点,我们可以,很容易总结出我们alloc源码的编译流程。

先说结论,编译的具体流程如下

1487527-bc778871d88fdd22

流程探究

接下来我们在按照这个顺序进行断点调试,我们现在allocobjc_alloc处打一个断点,运行程序,我们会发现我们的断电先停在的是objc_alloc内,查看网上的资料,这是因为LLVM 在编译阶段会将 alloc 符号替换为 objc_alloc 入口点。

image-20250423114756417

接着继续步入,断点情况如下

image-20250423115300414

进入alloc流程之中的核心callAlloc,对两个return打上断点,我们可以看到,自定义类在第一次进入callAlloc的时候,是会使用消息转发的方法,再去调用真正的alloc函数

image-20250423120018851

至于为何需要走两次callAlloc的原因我们先按下不表,接着程序再次调用callAlloc,这次我们会发现断点打在了_objc_rootAllocWithZone之中

请添加图片描述

进入函数看看
image-20250423194828460

这个函数内容过于复杂,等到下一篇文章再详细阐述,我们只要知道,这个程序是动态创建类实例的核心函数,用于分配内存并初始化实例的 isa 指针。

Objective-C 中自定义类的 alloc 方法调用流程涉及双重 callAlloc 的机制,其根源在于 类初始化延迟运行时多态性设计。以下是该流程的核心原因及分步解析:

1. 首次调用 objc_alloc
  • 入口id objc_alloc(Class cls) 是运行时提供的全局分配函数。
  • 目的
    • 检查类是否已初始化(cls->isRealized())。
    • 若未初始化,触发 class_initialize() 完成类加载。
2. 进入 callAlloc
  • 参数checkNil=trueallocWithZone=false
  • 逻辑
    • 检查类是否存在(slowpath(checkNil && !cls))。
    • 若类支持优化路径(未重写 allocWithZone:),直接调用 _objc_rootAllocWithZone
3. 动态派发 objc_msgSend
  • 触发条件:若类重写了 allocWithZone:,需通过消息发送调用自定义逻辑。
  • 结果:进入类的 +alloc 方法,最终再次调用 callAlloc
4. 第二次 callAlloc
  • 参数checkNil=falseallocWithZone=true
  • 逻辑
    • 直接调用 _objc_rootAllocWithZone,跳过安全检查。
    • 最终通过 _class_createInstanceFromZone 完成内存分配和 isa 绑定。

两次进入的区别

我们现在在来看看两次进入callAlloc究竟有什么区别

第一次调用 callAlloc 时,参数 checkNil=true,在程序之中需要验证类是否存在。

image-20250424121010777

第二次调用 callAlloc 时,参数 checkNil=false,跳过安全检查。

image-20250424121031770

其实差别就在于,后面传进的两个布尔值,其实就是是否需要进行安全检查。在第一次进入callAlloc会做一次检查,确保对应的类不为空。

为何自定义类需要进入两次callAlloc

static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{if (slowpath(checkNil && !cls)) return nil;if (fastpath(!cls->ISA()->hasCustomAWZ())) {return _objc_rootAllocWithZone(cls, nil);}// No shortcuts available.if (allocWithZone) {return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);}return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}

系统类(如 NSObject):

因为NSObject在编译时已完成isa指针的初始化。所以不需要经过两次callAlloc

只需要直接进入objc_alloc->callAlloc->_objc_rootAllocWithZone直接申请空间即可

自定义类:

  • 第一次 callAlloc 通过 objc_alloc 进入,目的是 检查类的初始化状态,类初次创建是没有默认的alloc/allocWithZone实现的所以继续向下执行进入到msgSend消息发送流程,为这个类进行初始化。

  • 第二次 callAlloc,此时类已初始化完成,进入实际内存分配逻辑。

  • callAlloc 的分支逻辑

    if (fastpath(!cls->ISA()->hasCustomAWZ())) {return _objc_rootAllocWithZone(cls, nil); // 直接分配内存
    } else {return objc_msgSend(cls, @selector(alloc)); // 通过消息发送调用自定义逻辑
    }
    
    • hasCustomAWZ():检测类是否重写了 allocWithZone: 方法。
    • 若未重写(默认情况),直接调用 _objc_rootAllocWithZone 分配内存。
    • 若重写,则通过 objc_msgSend 触发动态派发,确保调用正确的 alloc 实现。

    那么源码是如何查看缓存的呢,我们进入hasCustomAWZ()看一下

    #   define FAST_CACHE_HAS_DEFAULT_AWZ    (1<<14)
    bool hasCustomAWZ() const {return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);}bool getBit(uint16_t flags) const {return _flags & flags;}
    

    FAST_CACHE_HAS_DEFAULT_AWZ宏定义表示 是否实现alloc/allocWithZone位域标识位

    为了证明是类没有初始化的问题才导致callAlloc函数在类第一次被调用的时候被进入两次,我们可以通过在申请一次空间来尝试一下,断点和之前的一样。

    GGObject *obj = [GGObject alloc];
    GGObject *obj2 = [GGObject alloc];
    

    image-20250424141439512

    我们发现obj2的alloc调用顺序就和NSObject一样了。objc_alloc->callAlloc->_objc_rootAllocWithZone

    但紧接着问题又来了,重复进入callAlloc的原因我们找到了,那为什么要设置这个流程,这个所谓的类初始化实在哪里开始的呢?

    查看hasCustomAWZ()的调用栈可以看到,有个名字为 _objc_msgSend_uncached的方法,其实也很好理解,就是消息发送给了一个初始化信息的类之中,其实就是在消息转发这一步顺带把第一次调用的类进行初始化,然后在第二次进入hasCustomAWZ()就能进入

    _objc_rootAllocWithZone

image-20250424132737830

双重 callAlloc 流程是 Objective-C 运行时与编译器协作的产物,其核心目的是 确保类初始化完成兼容自定义内存分配逻辑。这一机制平衡了性能、灵活性与安全性,是 Objective-C 动态特性的典型体现。

init

其实点进去init, 很简单,就是把内容返回一次,如此设计的原因是为了让整个程序符合工厂模式的设计理念,我们可以通过简单的重新init的方法去实现较为复杂的其他操作。

image-20250424164807997

总结

其实我是想讲整一个alloc的流程梳理完整再将内容发出,无奈一个完完整整的流程涉及的内容实在过多,有想要了解的可以看 OC对象底层内存开辟和实现(中)了解初始化类的完整流程

参考资料

iOS-底层原理 02:alloc & init & new 源码分析

iOS-底层原理 04:NSObject的alloc 源码分析

OC对象底层内存开辟和实现(中)

相关文章:

「OC」源码学习——alloc与init的实现

「OC」源码学习——alloc与init的实现 前言 费劲千辛万苦终于项目给写完了&#xff0c;进入下一个阶段&#xff0c;源码的学习 alloc的调用顺序 我们在main函数之中打上断点&#xff0c;先运行 再在alloc之中的各个函数之中打上断点&#xff0c;在关键步骤上打上断点&#…...

AOSP Android14 Launcher3——动画核心类QuickstepTransitionManager详解

Launcher3中&#xff0c;有一个类在跟桌面相关的各种动画中扮演着非常关键的角色&#xff0c;这个类就是QuickstepTransitionManager。 QuickstepTransitionManager在aosp中的路径为&#xff1a;aosp/packages/apps/Launcher3/quickstep/src/com/android/launcher3/QuickstepT…...

STM32:看门狗

独立看门狗 简介 独立看门狗&#xff08;IWDG&#xff09;由独立的低速时钟&#xff08;LSI&#xff09;驱动&#xff0c;即便主时钟发生故障&#xff0c;它依然能够正常工作。其主要作用是在程序出现异常时&#xff0c;通过复位来保障系统的稳定性。独立看门狗的喂狗操作相对…...

第十三步:vue

Vue 1、上手 1、安装 使用命令&#xff1a;npm create vuelatestvue文件后缀为.vueconst app createApp(App)&#xff1a;初始化根组件app.mount("#app")&#xff1a;挂载根组件到页面 2、文件 script标签&#xff1a;编写jstemplate标签&#xff1a;编写htmls…...

《代码整洁之道》第8章 边界 - 笔记

甚至是你团队里其他组写的你无法随意修改的代码。 这些外部代码是你的**“边界”。它们可能会升级、可能会有 Bug、可能会有反人类的设计、甚至你将来可能想换一个类似的库或服务。如果你的应用代码直接且紧密地依赖**这些外部代码的具体类、方法、异常等细节&#xff0c;那么…...

【CF】Day45——Codeforces Round 1021 (Div. 2) BC

阅读理解。。。不过挺有意思&#xff08; B. Sasha and the Apartment Purchase 题目&#xff1a; 思路&#xff1a; 看了半天没看懂... 题目叽里咕噜一大堆&#xff0c;说白了就是让我们在一个 可删除k个数 的 数组 中选 一些点 且 这些点的f(x) 是此时 删完了k个数之后的数组…...

《代码整洁之道》第5章 格式 - 笔记

你应该选择一套管理代码格式的简单规则。如果是团队&#xff0c;应该选择一套团队一致同意采用的简单格式规则。 最重要的原则&#xff1a;一致性&#xff08;Consistency&#xff09;&#xff01; 没有完美的格式规范&#xff0c;但有统一的规范。 整个团队&#xff08;或者…...

通过示例学习:连续 XOR

通过示例学习&#xff1a;连续 XOR 如果我们想在 PyTorch 中构建神经网络&#xff0c;可以使用 &#xff08;with&#xff09; 指定所有参数&#xff08;权重矩阵、偏差向量&#xff09;&#xff0c;让 PyTorch 计算梯度&#xff0c;然后调整参数。但是&#xff0c;如果我们有很…...

加密算法 AES、RSA、MD5、SM2 的对比分析与案例(AI)

加密算法 AES、RSA、MD5、SM2 的对比分析 一、相同点 ‌密码学基础‌ 均为现代密码学核心算法&#xff0c;用于保障数据安全。‌数据处理‌ 均涉及数据转换&#xff08;加密、签名、哈希等&#xff09;。‌密钥依赖‌ AES、RSA、SM2 依赖密钥&#xff08;对称或非对称&#x…...

基于STM32、HAL库的MAX31865模数转换器ADC驱动程序设计

一、简介: MAX31865是一款高精度的铂电阻温度检测器(RTD)至数字转换器,具有以下特点: 支持2线、3线或4线RTD配置 15位ADC分辨率 可编程RTD和基准电阻 内置故障检测(开路、短路等) SPI接口通信 工作电压:3.0V至3.6V 二、硬件接口: STM32L4XX <--> MAX31865 PA5(SCK…...

Laravel5.7的一些用法

1、事件需要运行 php artisan queue:work 2、数据库对象关联 1对1 hasOne 1对多 hasMany 1依赖多 belongsTo 多依赖多 belongsToMany 3、 关联查询 with 关联统计 withCount 统计时指定字段名。 如: withCount([cardHolderOrders as order_count]); 4、 // 一次查询&…...

Vue3 + OpenLayers 开发教程 (六)WebGL渲染优化

1. WebGL 渲染优化 1.1 WebGL 渲染器配置 创建 src/utils/webgl.ts&#xff1a; import { Map } from ol; import { WebGLPointsLayer } from ol/layer; import { Vector as VectorSource } from ol/source; import { Style, Circle, Fill, Stroke } from ol/style;// 创建 …...

【C++】C++11新特性(一)

文章目录 列表初始化initializer_list左值引用和右值引用 列表初始化 在 C98 中可以使用{}对数组或者结构体元素进行统一的列表初始值设定 struct Point {int _x;int _y; }; int main() {int array1[] { 1, 2, 3, 4, 5 };int array2[5] { 0 };Point p { 1, 2 };return 0; …...

【网络原理】 网络编程套接字

文章目录 一、网络编程基础1. 为什么需要网络编程&#xff1f;2. 什么是网络编程3 .网络编程中的基本概念发送端和接收端请求和响应客户端和服务端 4. 常见的客户端服务端模型 二、Socket套接字1. 概念2.分类3. Java数据报套接字通信模型4.Java流套接字通信模型 三、UDP数据报套…...

每天五分钟深度学习框架pytorch:使用visdom绘制损失函数图像

visdom的安装 pip install visdom如果安装失败 pip install --upgrade visdom开启visdom python -m visdom.server nohup python -m visdom.server后台启动然后就会出现,下面的页面,我们可以使用下面的链接打开visdom页面 Visdom中有两个重要概念: env环境。不同环境的可…...

【MySQL专栏】MySQL数据库表的内外连接

文章目录 1、表的内连接&#xff08;1&#xff09;内连接的语法格式①显示SMITH的名字和部门名称 2、外连接&#xff08;1&#xff09;左外连接左外连接的语法格式通过实例演示&#xff1a; &#xff08;2&#xff09;右外连接右外连接的语法格式通过实例演示 1、表的内连接 什…...

-信息革命-

信息革命-马歇尔麦克卢汉&#xff08;MARSHALL McLUHAN&#xff09;&#xff0c;1964年 随着大系统的加速崩溃&#xff0c;作为塑造经济生活和收入分配的一个因素&#xff0c;系统性的强 制将会式微。很快&#xff0c;在社会机构的组织中&#xff0c;效率将会比权力的分配更加重…...

Charles 抓包入门教程

一、什么是 Charles&#xff1f; Charles 是一款功能强大的抓包工具&#xff0c;可以拦截、查看、分析电脑和手机上的 HTTP/HTTPS 网络请求。常用于&#xff1a; 查看网页或App发送的请求和返回的数据调试接口、分析问题模拟网络环境&#xff08;断网、慢速网络&#xff09;修…...

深度学习新趋势:利用MLP取代卷积层——S2-MLPv2模型解析

深度学习新趋势&#xff1a;利用MLP取代卷积层——S2-MLPv2模型解析 近年来&#xff0c;深度学习领域不断涌现出新的技术革新&#xff0c;而其中最引人注目的趋势之一就是用多层感知机&#xff08;MLP&#xff09;替代传统的卷积层。这种转变不仅带来了计算效率的提升&#xf…...

【玩转 JS 函数式编程_016】DIY 实战:巧用延续传递风格(CPS)重构倒计时特效逻辑

文章目录 巧用延续传递风格&#xff08;CPS&#xff09;重构倒计时特效逻辑1 起因2 换一种思路3 填坑之旅4 复盘与小结 写在前面 都说念念不忘&#xff0c;必有回响。写过的文章也好&#xff0c;看过的视频也罢&#xff0c;其实只要用心积累&#xff0c;不必刻意去死记硬背&…...

虚函数表的设计和多态的实现

虚表指针 类直接定义虚函数&#xff1a;编译器自动在对象头部插入 vptr。 继承含虚函数的父类&#xff1a;子类复用父类的 vptr&#xff0c;不会创建新的vptr 单继承&#xff08;子类继承一个含虚函数的父类&#xff09; 1.创建新的虚函数表 2.沿用父类的虚表指针&#xff…...

中国科学院大学计算机考研历年初试分数线分析以及计算机所考的科目有哪些?

以下是对中国科学院大学计算机考研历年初试分数线分析以及计算机所考科目的介绍&#xff1a; 历年初试分数线分析 • 2024 年 &#xff1a;计算机应用技术专业&#xff08;专业代码 081203&#xff09;和计算机技术专业&#xff08;专业代码 085404&#xff09;的复试分数线为…...

Simulink与C的联合仿真调试

背景 simulink的Matlab Function&#xff0c;默认采用double类型的数据&#xff0c;无法定制int或者single类型的数据&#xff1b;Simulink中的Matlab Function直接调用.m文件中的函数&#xff08;该函数中对数据类型有single或者int的定义&#xff09;&#xff0c;该函数中的…...

DeepSeek 多头潜在注意力(Multi-Head Latent Attention, MLA)技术

1. 核心原理 多头潜在注意力&#xff08;MLA&#xff09;是Transformer架构的扩展技术&#xff0c;通过潜在空间投影和多注意力头并行计算增强模型对长序列和复杂特征的建模能力。 1.1 关键技术点 潜在空间压缩 将原始高维注意力矩阵投影到低维潜在空间&#xff0c;降低计算复…...

C# 类(Class)教程

在现代面向对象编程中&#xff0c;**类&#xff08;Class&#xff09;**是最基础、最重要的概念之一。通过学习类&#xff0c;我们可以理解怎样定义自己的数据类型&#xff0c;封装数据与行为&#xff0c;构建复杂的软件体系结构。本文将详细介绍C#中的类&#xff0c;从基础定义…...

Kubernetes学习笔记-环境变量的使用

如果项目需要一些灵活配置&#xff0c;减少硬编码或者避免敏感信息的暴露&#xff0c;可以考虑使用Kubernetes Pod下的容器的环境变量。 Pod容器设置环境变量的方式&#xff1a; 可以通过Deployment配置文件的env字段来设置环境变量 value env:- name: ACTIVE_PROFILEvalue: …...

git提交规范记录,常见的提交类型及模板、示例

Git提交规范是一种约定俗成的提交信息编写标准&#xff0c;旨在使代码仓库的提交历史更加清晰、可读和有组织。以下是常见的Git提交类型及其对应的提交模板&#xff1a; 提交信息的基本结构 一个标准的Git提交信息通常包含以下三个主要部分&#xff1a; Header‌&#xff1a;描…...

关于指针和指针算术

第一次读C primer plus 第六版时&#xff0c;关于指针的语法一些名词没有用心去理解&#xff0c;再读的时候&#xff0c;讲到指针算术这个词时&#xff0c;感觉之前读像是漏了很关键的点&#xff0c;这次读&#xff0c;写下关于指针算术的思考。 有漏了的感觉是&#xff0c;在…...

el-input限制输入只能是数字 限制input只能输入数字

方法一&#xff1a; 通过设置type属性&#xff1a;type“number”&#xff0c;这种方式一般会影响样式&#xff0c;不建议使用&#xff0c;如下图&#xff1a; <el-input type"number" v-model"aaa"></el-input>方法二&#xff1a; 通过绑定值…...

Pydantic:校验器(@validator)、模型嵌套、模型继承

&#x1f4da; 1. 校验器&#xff08;validator&#xff09; Pydantic 允许你自定义字段验证逻辑。用 validator 装饰器可以在字段赋值时自动进行检查或修改。 例子&#xff1a; from pydantic import BaseModel, validatorclass User(BaseModel):name: strage: intvalidato…...

343. 整数拆分

给定一个正整数 n&#xff0c;将其拆分为至少两个正整数的和&#xff0c;并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: 输入: 2输出: 1解释: 2 1 1, 1 1 1。 示例 2: 输入: 10输出: 36解释: 10 3 3 4, 3 3 4 36。说明: 你可以假设 n 不小于 2…...

前端面试 js

作用域链 内存管理 垃圾回收器 引用计数 默认栈里面会有一次引用 问题&#xff1a;循环引用&#xff0c;会产生内存泄漏 标记清除 垃圾回收期会定期从根开始遍历&#xff0c;找到有引用的对象 闭包 内存泄漏 this的指向 默认绑定 独立调用的this都是window function foo()…...

Linux CentOS 安装Python 3.8.0

在 CentOS 上升级 Python 3.6.8 到 3.8.0&#xff0c;可以按照以下步骤操作&#xff1a; 1. 安装依赖 sudo yum groupinstall -y "Development Tools" sudo yum install -y openssl-devel bzip2-devel libffi-devel zlib-devel wget 如果遇到报错“File "/bin…...

EXCEL常用函数公式和VBA汇总第二篇

系列文章目录 文章目录 系列文章目录前言一、excel公式应用1.rand函数2.rand函数随机排序3.rand函数提取数据4.correl函数5.SUBSTITUTE函数6.MAX组合函数7.分析下班时间8.柏拉图自动排序 总结 前言 一、excel公式应用 1.rand函数 用excel生成1-5的随机数字&#xff0c;其中对…...

Python 基础核心知识

1. Python 特点 简洁易读&#xff1a;代码简洁&#xff0c;强制缩进&#xff08;取代花括号&#xff09;。动态类型&#xff1a;变量无需声明类型&#xff08;如 x 10&#xff09;。跨平台&#xff1a;支持 Windows、Linux、macOS。丰富的库&#xff1a;如 NumPy&#xff08;…...

软考:软件设计师考试数据结构知识点详解

文章目录 1. 引言1.1 数据结构的重要性1.2 软件设计师考试中数据结构的考察目标 2. 基本概念和术语2.1 数据结构的定义2.2 算法和数据结构的关系2.3 抽象数据类型&#xff08;ADT&#xff09; 3. 线性结构3.1 数组3.1.1 数组的定义和特点3.1.2 数组的存储结构3.1.3 数组的优缺点…...

11前端项目总结----详情页放大镜和轮播图

商品详情页 DOM元素尺寸和位置相关属性1. 尺寸相关属性2.位置相关属性3.鼠标事件相关位置属性 放大镜排他Swiper和组件通信 DOM元素尺寸和位置相关属性 1. 尺寸相关属性 ①offsetWidth/offsetHeight&#xff1a;内容宽度/高度paddingborder&#xff08;滚动条&#xff09; ②c…...

Linux课程五课---Linux进程认识1

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…...

Nacos简介—4.Nacos架构和原理一

大纲 1.Nacos的定位和优势 2.Nacos的整体架构 3.Nacos的配置模型 4.Nacos内核设计之一致性协议 5.Nacos内核设计之自研Distro协议 6.Nacos内核设计之通信通道 7.Nacos内核设计之寻址机制 8.服务注册发现模块的注册中心的设计原理 9.服务注册发现模块的注册中心的服务数…...

splitchunk(如何将指定文件从主包拆分为单独的js文件)

1. 说明 webpack打包会默认将入口文件引入依赖js打包为一个入口文件&#xff0c;导致这个文件会比较大&#xff0c;页面首次加载时造成加载时间较长 可通过splitchunk配置相应的规则&#xff0c;对匹配的规则打包为单独的js,减小入口js的体积 2. 示例 通过正则匹配&#xff…...

MCP+A2A协议终极指南:AI系统构建技术全解析(医疗/金融实战+Streamable HTTP代码详解)

简介 2025年,MCP协议与A2A协议成为AI系统互联的核心技术。本文从通信机制到企业级应用,结合Streamable HTTP、零信任安全、多模态处理等最新技术,提供Go/Python/Java多语言实战代码,覆盖医疗诊断、金融风控等场景。含15+完整案例、性能优化方案及安全架构设计,助你掌握下…...

关于定时任务原理

关于定时任务原理 计算机是怎么计时的关于本地定时任务实现小根堆实现时间轮实现 关于分布式任务的实现管理未来的执行时间点 今天来聊一下工作中经常使用的定时任务的底层实现原理 计算机是怎么计时的 计算机内部使用多种方式来计时&#xff0c;主要依赖于硬件时钟&#xff0…...

【vue3】购物车实战:从状态管理到用户体验的全流程实现

在电商项目中&#xff0c;购物车是核心功能之一&#xff0c;需要兼顾数据一致性、用户体验和逻辑复杂度。 本文结合 Vue3 Pinia 技术栈&#xff0c;详细讲解如何实现一个高效且易用的购物车系统&#xff0c;重点剖析 添加购物车 和 头部购物车预览 的核心逻辑与实现细节。 一…...

日本IT|UIUX主要的工作都是哪些?及职业前景

在日本IT行业中&#xff0c;UI/UX&#xff08;用户界面/用户体验&#xff09;设计的工作涵盖从用户研究到界面实现的全流程&#xff0c;尤其在数字化服务、电商、金融科技等领域需求旺盛。 本篇是UI/UX在日本的主要工作内容、行业特点及职业前景分析&#xff1a; 一、UI/UX的主…...

Tailwind CSS 实战:基于 Kooboo 构建企业官网页面(二)

基于上篇内容&#xff0c;继续完善企业官网页面&#xff1a; Tailwind CSS 实战&#xff1a;基于 Kooboo 构建企业官网页面&#xff08;一&#xff09; 3.3 服务亮点&#xff1a;用于展示企业主要的服务项 1. 整体结构&#xff1a; <section class"py-16">&…...

第7章 内部类与异常类

7.1 内部类 在一个类中定义另一个类&#xff0c;这样的类称为内部类&#xff0c;包含内部类的类称为内部类的外部类。 关系&#xff1a; 内部类的外嵌类的成员变量在内部类中仍然有效&#xff0c;内部类中的方法也可以调用外嵌类中的方法。 内部类的类体中不可以声明类变量和…...

优先队列、堆笔记(算法第四版)

方法签名描述构造函数MaxPQ()创建一个优先队列MaxPQ(int max)创建一个初始容量为 max 的优先队列MaxPQ(Key[] a)用 a[] 中的元素创建一个优先队列普通方法void insert(Key v)向优先队列中插入一个元素Key max()返回最大元素Key delMax()删除并返回最大元素boolean isEmpty()返回…...

7.14 GitHub命令行工具测试实战:从参数解析到异常处理的全链路测试方案

GitHub命令行工具测试实战:从参数解析到异常处理的全链路测试方案 GitHub Sentinel Agent 用户界面设计与实现:测试命令行工具 关键词:命令行工具测试, 接口集成测试, 参数化测试, 异常处理测试, 测试覆盖率分析 1. 命令行工具测试架构设计 通过三层测试体系保障 CLI 工具…...

使用CubeMX新建USART1不定长接收工程

目录 1、新建板级支持包 2、修改中断服务函数 3、修改main.c文件 4、程序流程 新建工程的基本操作步骤参考这里&#xff1a;STM32CubeMX学习笔记&#xff08;6&#xff09;——USART串口使用_unused(huart)-CSDN博客 1、新建板级支持包 在本地保存新建工程的文件夹中新建Us…...

【C++QT】Layout 布局管理控件详解

文章目录 一、QVBoxLayout 垂直布局1.1 特点1.2 常用方法1.3 应用场景1.4 示例代码 二、QHBoxLayout 水平布局2.1 特点2.2 常用方法2.3 应用场景2.4 示例代码 三、QGridLayout 网格布局3.1 特点3.2 常用方法3.3 应用场景3.4 示例代码 四、QFormLayout 表单布局4.1 特点4.2 常用…...