Objective-C Block 底层原理深度解析
Objective-C Block 底层原理深度解析
1. Block 是什么?
1.1 Block 的本质
- Block 是 Objective-C 中的特殊对象,实现了匿名函数的功能
- 通过 isa 指针继承自 NSObject,可以响应(如 copy、retain、release)等内存管理方法(ARC 下自动处理)。
- 遵循 Objective-C 的内存管理规则
- 可以临时保存代码并在需要时执行
- 可以访问定义时的上下文变量
- 可以像普通对象一样传递和使用
1.2 Block 的基本写法
// 最简单的 Block
void (^sayHello)(void) = ^{NSLog(@"Hello");
};// 带参数的 Block
void (^saySomething)(NSString *) = ^(NSString *words) {NSLog(@"%@", words);
};// 带返回值的 Block
int (^add)(int, int) = ^(int a, int b) {return a + b;
};
1.3 Block 的底层结构
// Block 的本结构
struct Block_layout {void *isa; // 指向类对象,证明 Block 是对象int flags; // 状态标志,包含 Block 的类型和引用计数信息int reserved; // 保留字段void (*invoke)(void *, ...); // 函数指针,指向 Block 的实现代码struct Block_descriptor *descriptor; // 描述信息,包含 Block 的大小、复制和释放函数等// 捕获的变量
};
结构解析:
isa
指针:表明 Block 是一个对象,指向其类型信息(_NSConcreteGlobalBlock
、_NSConcreteStackBlock
或_NSConcreteMallocBlock
)Flags
:记录 Block 的状态信息,如是否被复制到堆上、是否包含 C++ 对象等reserved
:保留字段,用于未来扩展invoke
:指向 Block 要执行的代码descriptor
:包含 Block 的描述信息,如大小、复制和释放函数等- 这个结构体是 Block 作为对象和函数双重身份的基础
补充说明:
- Block 是特殊的 Objective-C 对象,可以响应
copy
、release
等消息 - 内存管理遵循 Objective-C 的内存管理规则
- 在编译时会根据使用场景生成不同的类型(全局、栈、堆)
- 结构体中的
isa
指针决定了 Block 的类型和行为
1.4 Block 的类型编码
// 基本格式:@?<返回值类型参数1类型参数2类型...>
// 示例1:无参数无返回值的 Block
"@?<v>" // void (^)(void)// 示例2:带基本类型参数的 Block
"@?<vi>" // void (^)(int)
// v 表示返回值类型为 void
// i 表示参数类型为 int (注意:基本类型不需要@前缀)// 示例3:带对象参数的 Block
"@?<v@>" // void (^)(id)
// v 表示返回值类型为 void
// @ 表示参数类型为 id(对象类型)// 示例4:带 Block 参数的 Block
"@?<v@?" // void (^)(void (^)())
// v 表示返回值类型为 void
// @? 表示参数类型为 Block// 示例5:带返回值的 Block
"@?<i@>" // int (^)(id)
// i 表示返回值类型为 int (基本类型不需要@前缀)
// @ 表示参数类型为 id// 示例6:带多个参数的 Block
"@?<viB@>" // void (^)(int, BOOL, id)
// v 表示返回值类型为 void
// i 表示第一个参数为 int
// B 表示第二个参数为 BOOL
// @ 表示第三个参数为 id
类型编码规则:
基本类型(int、BOOL等)不需要加@前缀
返回值类型如果是对象,需要加@
参数列表中的类型按顺序排列,不需要分隔符
对于具体类名的对象,可以使用@"ClassName"格式
@?
:表示这是一个 Block 类型< >
:包含 Block 的签名信息- 格式:
<返回值类型参数1类型参数2类型...>
- 返回值类型在前,参数类型依次排列
- 格式:
- 类型表示
- 基本类型:
v
:voidi
:intc
:charB
:BOOLf
:floatd
:doubleq
:NSIntegerQ
:NSUInteger
- 对象类型:
- @: id/NSObject
- @“NSString”: NSString* (具体类名)
- Block类型:
- @?: 另一个Block
- 基本类型:
// 复杂示例
typedef NSString *(^ComplexBlock)(int, void (^)(BOOL), NSArray<NSNumber *> *);// 对应的类型编码
"@?<@i@?@>"
// 或更精确的(如果希望包含类名):
"@?<@"NSString"i@?@"NSArray">"
逐部分解析:
部分 | 编码 | 对应类型 |
---|---|---|
返回值 | @ 或 @“NSString” | NSString * |
参数1 | i | int(基本类型,不加 @) |
参数2 | @? | void (^)(BOOL)(Block 参数) |
参数3 | @ 或 @“NSArray” | NSArray *(对象类型) |
2. Block 的三种类型
2.1 全局 Block(Global Block)
// 定义在全局作用域
void (^globalBlock)(void) = ^{NSLog(@"我是全局 Block");
};
特点:
- 不访问任何外部变量,完全独立于上下文
- 作为单例对象存储在程序的数据区,生命周期与程序相同
- 不需要特别的内存管理,由系统自动管理
- 性能最优,因为不需要捕获变量和内存管理开销
2.2 栈 Block(Stack Block)
- (void)example {int num = 10;void (^stackBlock)(void) = ^{NSLog(@"我是栈 Block: %d", num);};
}
特点:
- 访问外部变量,需要捕获上下文中的变量
- 作为临时对象存储在栈上,生命周期与所在函数相同
- 函数执行结束后可能失效,需要复制到堆上才能长期使用
- 性能较好,但需要注意使用时机和生命周期
2.3 堆 Block(Malloc Block)
- (void)example {int num = 10;// 方式1:手动复制到堆void (^heapBlock1)(void) = [^{NSLog(@"我是堆 Block: %d", num);} copy];// 方式2:赋值给属性自动复制到堆self.block = ^{NSLog(@"我是堆 Block: %d", num);};
}
特点:
- 由栈 Block 复制而来,存储在堆上,可以长期使用
- 需要管理内存,在 ARC 环境下由系统自动管理
- 可以安全地跨函数传递和使用
- 性能相对较低,但提供了最大的灵活性和安全性
2.4 内存管理差异
类型转换规则(ARC vs MRC)
操作场景 | ARC 环境 | MRC 环境 |
---|---|---|
赋值给 strong 变量 | 自动 copy 到堆 | 需要手动调用 copy |
作为函数返回值 | 自动 copy 到堆 | 需要手动调用 copy |
传递给 GCD API | 自动 copy 到堆 | 自动 copy 到堆 |
作为属性(copy) | 自动处理 | 必须显式 copy |
作为局部变量 | 保持在栈上 | 保持在栈上 |
作为全局变量 | 保持在数据区 | 保持在数据区 |
3. Block 如何捕获变量
3.1 基本类型变量
int num = 10;
void (^block)(void) = ^{NSLog(@"%d", num); // 只能读取,不能修改
};
编译后的结构:
// 编译器生成的 Block 结构体
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int num; // 捕获的变量
};// 使用示例
struct __main_block_impl_0 block = {.impl = {...},.Desc = {...},.num = 10 // 值复制
};
特点:
- 在编译时,Block 会创建一个结构体来存储捕获的变量
- 变量的值会被复制到 Block 的结构体中,形成独立的副本
- Block 内部使用的是这个副本,与外部变量完全独立
- 这种值复制机制保证了 Block 执行时数据的稳定性
3.2 使用 __block 修饰符
__block int num = 10;
void (^block)(void) = ^{num = 20; // 可以修改NSLog(@"%d", num);
};
编译后的结构:
// __block 变量的包装结构体
struct __Block_byref_num_0 {void *__isa;__Block_byref_num_0 *__forwarding;int __flags;int __size;int num; // 原始变量
};// Block 结构体
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_num_0 *num; // 通过指针引用
};
特点:
__block
修饰符会将被修饰的变量包装成一个结构体- 这个结构体包含原始变量的指针,使得 Block 可以修改原始变量
- 在 Block 被复制到堆上时,这个结构体也会被复制
- 所有引用这个变量的 Block 共享同一个结构体,保证修改的同步性
3.3 对象类型变量
NSObject *obj = [[NSObject alloc] init];
void (^block)(void) = ^{NSLog(@"%@", obj); // 强引用
};
编译后的结构:
// Block 结构体
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;NSObject *__strong obj; // 强引用// 编译器生成的辅助函数void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*) = __main_block_copy_0;void (*dispose)(struct __main_block_impl_0*) = __main_block_dispose_0;
};
特点:
- 对象类型的变量在 Block 中默认是强引用
- Block 会通过
retain
操作增加对象的引用计数 - 当 Block 被复制到堆上时,会再次
retain
对象 - 需要注意循环引用问题,可以使用
__weak
修饰符来避免 - 在 ARC 环境下,Block 会自动管理对象的引用计数
底层实现原理:
- Block 在编译时会生成一个结构体,包含捕获的变量
- 对于基本类型,直接复制值到结构体中
- 对于
__block
变量,会生成一个包装结构体 - 对于对象类型,会生成相应的引用计数管理代码
- Block 的
copy
操作会递归复制所有捕获的变量
3.4 小结
- 编译时处理:Block 在编译时会生成包含捕获变量的结构体,并根据变量类型生成相应的内存管理代码和辅助函数。
- 变量捕获方式:基本类型通过值复制形成独立副本,
__block
变量通过包装结构体实现共享访问,对象类型通过引用计数管理实现内存管理。 - 内存管理特点:基本类型无需特殊管理,
__block
变量通过共享结构体实现同步修改,对象类型通过自动引用计数管理生命周期。 - 性能考虑:基本类型性能最优,
__block
变量有指针间接访问开销,对象类型有引用计数管理开销。
4. Block 的内存管理与循环引用
4.1 内存管理规则
- 全局 Block:作为单例对象存储在数据区,生命周期与程序相同,无需特殊管理。
- 栈 Block:作为临时对象存储在栈上,在赋值给 strong 属性、作为返回值或传递给 GCD 时会自动复制到堆上。
- 堆 Block:由栈 Block 复制而来,在 ARC 环境下自动管理内存,遵循普通对象的内存管理规则。
4.2 循环引用问题与解决方案
循环引用示例
@interface DownloadManager : NSObject
@property (nonatomic, copy) void (^progressBlock)(CGFloat progress);
@property (nonatomic, copy) void (^completionBlock)(void);
@end@interface ViewController : UIViewController
@property (nonatomic, strong) DownloadManager *downloadManager;
@end@implementation ViewController
- (void)setup {// 错误写法:形成循环引用self.downloadManager = [[DownloadManager alloc] init];// 下载进度回调self.downloadManager.progressBlock = ^(CGFloat progress) {// ViewController 持有 downloadManager// progressBlock 持有 ViewController[self updateProgress:progress]; // 直接使用 self 导致循环引用};// 下载完成回调self.downloadManager.completionBlock = ^{// ViewController 持有 downloadManager// completionBlock 持有 ViewController[self handleDownloadComplete]; // 直接使用 self 导致循环引用};
}- (void)updateProgress:(CGFloat)progress {// 更新进度条
}- (void)handleDownloadComplete {// 处理下载完成
}
@end
循环引用分析:
- ViewController 持有 downloadManager(强引用)
- downloadManager 持有 progressBlock 和 completionBlock(copy 属性)
- progressBlock 和 completionBlock 都持有 ViewController(通过 self)
- 形成循环引用链:ViewController -> downloadManager -> Block -> ViewController
- 导致内存泄漏:这些对象都无法被释放
解决方案:
- 使用
__weak
修饰符打破循环引用 - 在 Block 内部使用 weak-strong dance 确保对象不会被释放
- 注意对象之间的引用关系,合理使用 weak 属性
正确写法:
@implementation ViewController
- (void)setup {self.downloadManager = [[DownloadManager alloc] init];// 使用 weak 引用打破循环__weak typeof(self) weakSelf = self;// 下载进度回调self.downloadManager.progressBlock = ^(CGFloat progress) {__strong typeof(weakSelf) strongSelf = weakSelf;[strongSelf updateProgress:progress];};// 下载完成回调self.downloadManager.completionBlock = ^{__strong typeof(weakSelf) strongSelf = weakSelf;[strongSelf handleDownloadComplete];};
}
@end
4.3 内存管理注意事项
- 在 MRC 环境下,堆 Block 需要手动管理内存(copy/release)
- 在 ARC 环境下,编译器会自动插入适当的内存管理代码
- 使用
__block
修饰的变量在 Block 复制到堆时也会被复制 - 对象类型的变量在 Block 中默认是强引用,需要注意循环引用问题
5. Block 的使用技巧
5.1 异步编程
在 iOS 开发中,Block 最常用的场景之一就是异步编程。通过 Block 可以优雅地处理异步操作的结果,避免回调地狱。
示例:数据加载
// 定义回调 Block 类型
typedef void (^Completion)(id result, NSError *error);- (void)loadData:(Completion)completion {// 在后台线程执行耗时操作dispatch_async(dispatch_get_global_queue(0, 0), ^{id result = [self fetchData];NSError *error = nil;// 回到主线程更新 UIdispatch_async(dispatch_get_main_queue(), ^{if (completion) {completion(result, error);}});});
}
使用说明:
- 使用
typedef
定义 Block 类型,提高代码可读性 - 在后台线程执行耗时操作,避免阻塞主线程
- 在主线程回调,确保 UI 更新操作安全
- 使用
if (completion)
检查 Block 是否存在
5.2 链式调用
Block 还可以用于实现链式调用语法,使代码更加流畅和易读。这种模式在构建对象时特别有用。
示例:Person 对象构建
@interface Person : NSObject
- (Person *(^)(NSString *))name;
- (Person *(^)(NSInteger))age;
@end@implementation Person
- (Person *(^)(NSString *))name {return ^Person *(NSString *name) {_name = name;return self; // 返回 self 实现链式调用};
}
@end// 使用示例
Person *person = [[Person alloc] init];
person.name(@"张三").age(20); // 链式调用
使用说明:
- 每个方法返回一个 Block,Block 返回 self
- 通过返回 self 实现链式调用
- 代码更加简洁,可读性更好
- 适合构建复杂对象时的配置
6. Block 的实际应用
6.1 回调处理
在 iOS 开发中,Block 广泛用于各种回调场景,如网络请求、数据加载等。
示例:网络请求回调
- (void)requestData:(void (^)(NSArray *data, NSError *error))completion {[self.network requestWithCompletion:^(id response, NSError *error) {if (completion) {completion(response, error);}}];
}
使用说明:
- 使用 Block 处理异步操作的结果
- 支持错误处理和成功回调
- 代码结构清晰,易于维护
6.2 动画处理
UIKit 框架中的动画 API 大量使用 Block 来处理动画过程和完成回调。
示例:视图动画
[UIView animateWithDuration:0.3 animations:^{// 动画过程中的属性修改view.alpha = 0.5;view.frame = newFrame;} completion:^(BOOL finished) {// 动画完成后的处理if (finished) {[view removeFromSuperview];}}];
使用说明:
animations
Block 定义动画过程completion
Block 处理动画完成- 支持动画取消和完成状态判断
6.3 枚举处理
Foundation 框架中的集合类提供了基于 Block 的枚举方法,使集合操作更加灵活。
示例:数组遍历
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {// 处理每个元素if ([obj isEqual:targetObject]) {*stop = YES; // 可以提前终止遍历}
}];
使用说明:
- 支持获取元素索引
- 可以通过
stop
参数提前终止遍历 - 比传统的 for 循环更加灵活
7. Block 性能优化与调试技巧
7.1 性能优化建议
-
避免不必要的 Block 复制
全局 Block 无需 copy,栈 Block 仅在需要时复制到堆,注意 __block 变量会随 Block 一起复制。 -
减少捕获变量数量
仅捕获必要变量,避免大型对象,高频场景优先使用全局 Block。 -
强弱引用策略
外部用 __weak 防循环引用,内部转 __strong 保对象存活,避免内部频繁创建临时对象。 -
内存布局优化
高频访问变量前置,减少捕获变量总数,评估 __block 变量的替代方案。
7.2 调试技巧
-
Instruments 三剑客
Allocations 追踪内存生命周期,Leaks 检测循环引用,Time Profiler 分析执行耗时 -
使用 LLDB 调试 Block
(lldb) po block # 打印 Block 对象 (lldb) p/x (long)block->isa # 查看 Block 的类型 (lldb) p/x (int)block->flags # 查看 Block 的 flags (lldb) p *(struct __block_impl *)block # 查看 Block 捕获的变量
-
问题排查三板斧
- 类型验证:po [block class] + 检查 flags 判断堆栈类型
- 变量审计:p/x 查看地址偏移,验证复制行为
- 内存验证:Xcode Memory Graph 可视化引用,malloc_history 追溯分配堆栈
-
工具链推荐
- 基础分析:Instruments 三件套(Allocations/Leaks/Time Profiler)
- 深度调试:Memory Graph 直观测循环引用,MallocStackLogging 定位野指针
8. 总结
Block 是 Objective-C 中的特殊对象,通过 isa 指针继承自 NSObject,实现了匿名函数的功能。它有三种类型:全局 Block(不捕获变量,存储在数据区)、栈 Block(捕获变量,存储在栈上)和堆 Block(由栈 Block 复制而来,存储在堆上)。Block 可以捕获变量,对于基本类型采用值复制,使用 __block
修饰符可以修改捕获的变量,对象类型默认是强引用。在内存管理方面,Block 遵循 Objective-C 的内存管理规则,需要注意循环引用问题,可以通过 __weak
和 weak-strong dance 模式解决。Block 的类型编码使用 @?<返回值类型参数类型>
的格式,支持基本类型、对象类型和 Block 类型。在实际开发中,Block 广泛应用于异步编程、回调处理、动画和集合操作等场景,使代码更加简洁和灵活。
如果觉得本文对你有帮助,欢迎点赞、收藏、关注我,后续会持续分享更多 iOS 底层原理与实战经验!
相关文章:
Objective-C Block 底层原理深度解析
Objective-C Block 底层原理深度解析 1. Block 是什么? 1.1 Block 的本质 Block 是 Objective-C 中的特殊对象,实现了匿名函数的功能 通过 isa 指针继承自 NSObject,可以响应(如 copy、retain、release)等内存管理方…...

关于IDE的相关知识之二【插件推荐】
成长路上不孤单😊😊😊😊😊😊 【14后😊///计算机爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于ide插件推荐的相关内容!…...
Python+Streamlit实现登录页
PythonStreamlit实现登录页 Streamlit 是一个开源的 Python 库,专为数据科学家和机器学习工程师设计,用于快速构建交互式 Web 应用。 其核心功能与特点包括: 1.快速原型开发 2.交互式数据展示 3.极简开发 4.实时更新 5.内置组件 6.无前端依赖…...
RDD案例数据清洗
在 Spark 中,RDD(Resilient Distributed Dataset)是分布式数据集的基本抽象。数据清洗是数据预处理中的一个重要步骤,通常包括去除重复数据、过滤无效数据、转换数据格式等操作。以下是一个使用 RDD 进行数据清洗的完整示例。 示…...
按键精灵ios脚本新增元素功能助力辅助工具开发(三)
元素节点功能(iOSElement) 在按键精灵 iOS 新版 APP v2.2.0 中,新增了元素节点功能 iOSElement,该功能包含共 15 个函数。这一功能的出现,为开发者在处理 iOS 应用界面元素时提供了更为精准和高效的方式。通过这些函…...

Axure RP9:列表新增
文章目录 列表新增思路新增按钮操作说明保存新增交互设置列表新增 思路 利用中继器新增行实现列表新增功能 新增按钮操作说明 工具栏中添加新增图标及标签,在图标标签基础上添加热区;对热区添加鼠标单击时交互事件,同步插入如下动作:显示/隐藏动作,设置目标元件为新增窗…...

06 mysql之DML
一、什么是DML DML 用于操作数据库中的数据。主要命令包括: INSERT:添加数据SELECT:查询数据UPDATE:修改数据DELETE:删除数据 二、插入数据(INSERT) 2.1 插入单条记录 -- 插入学生记录&…...
游戏引擎学习第277天:稀疏实体系统
回顾并为今天定下基调 上次我们结束的时候,基本上已经控制住了跳跃的部分,达到了我想要的效果,现在我们主要是在等待一些新的艺术资源。因此,等新艺术资源到位后,我们可能会重新处理跳跃的部分,因为现在的…...

【最新版】likeshop连锁点餐系统-PHP版+uniapp前端全开源
一.系统介绍 likeshop外卖点餐系统适用于茶饮类的外卖点餐场景,搭建自己的一点点、奈雪、喜茶点餐系统。 系统基于总部多门店的连锁模式,拥有门店独立管理后台,支持总部定价和门店定价LBS定位点餐,可堂食可外卖。无论运营还是二开…...
机器学习之决策树模型:从基础概念到条件类型详解
机器学习之决策树模型:从基础概念到条件类型详解 摘要:本文深入探讨决策树模型的概念、构成以及不同条件类型。首先介绍决策树的基本结构和工作原理,随后详细阐述轴心对齐条件与倾斜条件、二元条件与非二元条件的差异及应用场景,…...
网络编程(一)网络编程入门
本节课学习TCP客户端和服务器端编程架构,其分为分为C/S(客户端/服务器模式)和B/S(浏览器/服务器架构模式)两种模式。接下来我们分别了解这两种模式 C/S模式 C/S模式:服务器首先先启动,并根据客…...
黑名单中的随机数-leetcode710
题目描述 给定一个整数 n 和一个 无重复 黑名单整数数组 blacklist 。设计一种算法,从 [0, n - 1] 范围内的任意整数中选取一个 未加入 黑名单 blacklist 的整数。任何在上述范围内且不在黑名单 blacklist 中的整数都应该有 同等的可能性 被返回。 优化你的算法&am…...

纯Java实现反向传播算法:零依赖神经网络实战
在深度学习框架泛滥的今天,理解算法底层实现变得愈发重要。反向传播(Backpropagation)作为神经网络训练的基石算法,其实现往往被各种框架封装。本文将突破常规,仅用Java标准库实现完整BP算法,帮助开发者: 1) 深入理解BP数学原理。2) 掌握面向对象的神经网络实现。3) 构建可…...

海纳思(Hi3798MV300)机顶盒遇到海思摄像头
海纳思机顶盒遇到海思摄像头,正好家里有个海思Hi3516的摄像头模组开发板,结合机顶盒来做个录像。 准备工作 海纳斯机顶盒摄像机模组两根网线、两个电源、路由器一块64G固态硬盘 摄像机模组和机顶盒都接入路由器的LAN口,确保网络正常通信。 …...
MCP项目实例 - client sever交互
1. 项目概述 项目目标 构建一个本地智能舆论分析系统。 利用自然语言处理和多工具协作,实现用户查询意图的自动理解。 进行新闻检索、情绪分析、结构化输出和邮件推送。 系统流程 用户查询:用户输入查询请求。 提取关键词:从用户查询中…...

Axure应用交互设计:表格跟随菜单移动效果(超长表单)
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!本文如有帮助请订阅 Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:表格跟随菜单移动 主要内容:表格交互设计、动态面板嵌套、拖动时事件、移动动作 应用场景…...

7系列 之 I/O标准和终端技术
背景 《ug471_7Series_SelectIO.pdf》介绍了Xilinx 7 系列 SelectIO 的输入/输出特性及逻辑资源的相关内容。 第 1 章《SelectIO Resources》介绍了输出驱动器和输入接收器的电气特性,并通过大量实例解析了各类标准接口的实现。 第 2 章《SelectIO Logic Resource…...

github 上的 CI/CD 的尝试
效果 步骤 新建仓库设置仓库的 page 新建一个 vite 的项目,改一下 vite.config.js 中的 base 工作流 在项目的根目录下新建一个 .github/workflows/ci.yml 文件,然后编辑一下内容 name: Build & Deploy Vue 3 Appon:push:branches: [main]permi…...
Scala和Go差异
Scala和Go(又称Golang)是两种现代编程语言,各自具有独特的特性和设计哲学。 尽管它们都可以用于构建高性能、可扩展的应用程序,但在许多方面存在显著差异。 Scala和Go的详细比较,涵盖它们的异同点: 1. 语…...

yup 使用 3 - 利用 meta 实现表单字段与表格列的统一结构配置(适配 React Table)
yup 使用 3 - 利用 meta 实现表单字段与表格列的统一结构配置(适配 React Table) Categories: Tools Last edited time: May 11, 2025 7:45 PM Status: Done Tags: form validation, schema design, yup 本文介绍如何通过 Yup 的 meta() 字段࿰…...
类初始化方法
一、类初始化方法 成员初始化列表 class Point {int x, y; public:Point(int a, int b) : x(a), y(b) {} };就地初始化(C11) 声明时初始化。 class Widget {int size 10; // 类内成员初始化vector<int> data{1,2,3}; };特殊情况:静…...

【OpenCV】imread函数的简单分析
目录 1.imread()1.1 imread()1.2 imread_()1.2.1 查找解码器(findDecoder)1.2.2 读取数据头(JpegDecoder-->readHeader)1.2.2.1 初始化错误信息(jpeg_std_error)1.2.2.2 创建jpeg解压缩对象(…...

【Linux实践系列】:进程间通信:万字详解共享内存实现通信
🔥 本文专栏:Linux Linux实践项目 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 人生就像一场马拉松,重要的不是起点,而是坚持到终点的勇气 ★★★ 本文前置知识: …...

【笔记】BCEWithLogitsLoss
工作原理 BCEWithLogitsLoss 是 PyTorch 中的一个损失函数,用于二分类问题。 它结合了 Sigmoid 激活函数和二元交叉熵(Binary Cross Entropy, BCE)损失在一个类中。 这不仅简化了代码,而且通过数值稳定性优化提高了模型训练的效…...
Oracle SYSTEM/UNDO表空间损坏的处理思路
Oracle SYSTEM/UNDO表空间损坏是比较棘手的故障,通常会导致数据库异常宕机进而无法打开数据库。数据库的打开故障处理起来相对比较麻烦,读者可以参考本书第5章进一步了解该类故障的处理过程。如果数据库没有备份,通常需要设置官方不推荐的隐含…...
为什么 cout<<“中文你好“ 能正常输出中文
一, 简答: 受python3字符串模型影响得出的下文C字符串模型结论 是错的!C的字符串和python2的字符串模型类似,也就是普通的字符串是ASCII字符串和字节串两种语义,类似重载或多态,有时候解释为整数,有时候是字节串。Uni…...
Leetcode 3547. Maximum Sum of Edge Values in a Graph
Leetcode 3547. Maximum Sum of Edge Values in a Graph 1. 解题思路2. 代码实现 题目链接:3547. Maximum Sum of Edge Values in a Graph 1. 解题思路 这一题主要是在问题的分析上面。由题意易知,事实上给定的图必然只可能存在三种可能的结构&#x…...

关于Go语言的开发环境的搭建
1.Go开发环境的搭建 其实对于GO语言的这个开发环境的搭建的过程,类似于java的开发环境搭建,我们都是需要去安装这个开发工具包的,也就是俗称的这个SDK,他是对于我们的程序进行编译的,不然我们写的这个代码也是跑不起来…...

Flutter PIP 插件 ---- 为iOS 重构PipController, Demo界面,更好的体验
接上文 Flutter PIP 插件 ---- 新增PipActivity,Android 11以下支持自动进入PIP Mode 项目地址 PIP, pub.dev也已经同步发布 pip 0.0.3,你的加星和点赞,将是我继续改进最大的动力 在之前的界面设计中,还原动画等体验一…...
Redis 基本命令与操作全面解析:从入门到实战
前言 Redis 作为高性能内存数据库,其丰富的命令体系是发挥强大功能的基础。掌握 Redis 的基本命令,不仅能实现数据的高效读写,还能深入理解其内存模型与工作机制。本文将系统梳理 Redis 的核心命令,涵盖连接操作、键管理、数据类…...