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)等内存管理方…...
AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】
AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】 AlDente Pro for Mac,是一款充电限制保护工具,是可以限制最大充电百分比来保护电池的工具。锂离子和聚合物电池(如 MacBook 中的电池)在40&…...
Linux systemd 从理论到实践:现代系统管理的核心工具
文章目录 引言:为什么需要 systemd?第一部分:systemd 核心理论1.1 systemd 的设计哲学1.2 核心组件1.3 单元文件(Unit File)结构 第二部分:实战操作指南2.1 基础命令2.2 服务管理高级操作2.3 日志管理&…...
分享一个移动端项目模板:React-Umi4-mobile
分享一个移动端项目模板:React-Umi4-mobile 大家好,今天想和大家分享一个我最近做的移动端项目模板 React-Umi4-mobile。 模板的主要内容 这个模板主要包括: 基于 Umi 4 框架使用了 antd-mobile 组件库配置了 px 自动转 vw(基…...
Tailwind CSS 响应式设计解析(含示例)
本文内容: Tailwindcss V4 中如何使用响应式设计功能,包括默认断点、自定义断点、断点范围控制以及容器查询的各种技巧,帮助你在不离开 HTML 的前提下优雅构建响应式页面。 🌟 默认断点用法(移动优先) Tail…...
ElasticSearch入门
1 elasticsearch概述 1.1 elasticsearch 简介 官网: https://www.elastic.co/ ElasticSearch是一个基于 Lucene 的搜索服务器,基于RESTful web接口。Elasticsearch是用Java开发的,开源的企业级搜索引擎。 Elastic官方宣布Elasticsearch进入Version 8…...
强化学习之基于无模型的算法之时序差分法
2、时序差分法(TD) 核心思想 TD 方法通过 引导值估计来学习最优策略。它利用当前的估计值和下一个时间步的信息来更新价值函数, 这种方法被称为“引导”(bootstrapping)。而不需要像蒙特卡罗方法那样等待一个完整的 episode 结束才进行更新&…...
【网络原理】TCP异常处理(二):连接异常
目录 一. 由进程崩溃引起的连接断开 二. 由关机引起的连接断开 三. 由断电引起的连接断开 四. 由网线断开引起的连接断开 一. 由进程崩溃引起的连接断开 在一般情况下,进程无论是正常结束,还是异常崩溃,都会触发回收文件资源,…...
[stm32] 4-1 USART(1)
文章目录 前言4-1 USARTUSART简介什么是USART?USART名字的含义?如何使用USART? USART的工作原理什么是串并转换?为什么要进行串并转换?移位寄存器串并行转换电路 USART寄存器组和完整框图 前言 本笔记内容,为本人依据…...
C++多线程与锁机制
1. 基本多线程编程 1.1 创建线程 #include <iostream> #include <thread>void thread_function() {std::cout << "Hello from thread!\n"; }int main() {std::thread t(thread_function); // 创建并启动线程t.join(); // 等待线程结束return 0; …...
【MCP Node.js SDK 全栈进阶指南】高级篇(4):自定义传输层开发
引言 在MCP(Model Context Protocol)应用开发中,传输层是连接客户端与服务器的关键环节,直接影响应用的性能、可靠性和扩展性。默认的传输方式虽然能满足基本需求,但在复杂场景下,自定义传输层能够为应用提供更高的灵活性和优化空间。本文将深入探讨MCP TypeScript-SDK中…...
当向量数据库与云计算相遇:AI应用全面提速
如果将AI比作一台高速运转的机器引擎,那么数据便是它的燃料。 然而,存储数据的燃料库--传统数据库,在AI时代的效率瓶颈愈发明显,已经无法满足AI对于数据的全新需求。 因此,向量数据库近年来迅速崛起。向量数据库通过…...
【2024-NIPS-版权】Evaluating Copyright Takedown Methods for Language Models
1.背景 目前 LLMs 在训练过程中使用了大量的受版权保护数据,这些数据会导致大模型记忆并生成与训练数据相似的内容,从而引发版权问题。随着版权所有者对模型训练和部署中的版权问题提起诉讼(例如 Tremblay v. OpenAI, Inc. 和 Kadrey v. Met…...
【PyTorch动态计算图原理精讲】从入门到灵活应用
目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比二、实战演示环境配置要求核心代码实现案例1:基础计算图构建案例2:条件分支动态图案例3:循环结构动态图运行结果验证三、性能对比测试方…...
阿里巴巴Qwen3发布:登顶全球开源模型之巅,混合推理模式重新定义AI效率
今天凌晨,阿里巴巴正式开源了新一代通义千问大模型Qwen3,这一举措不仅标志着国产大模型技术的又一里程碑,更以“混合推理”“极致性能”“超低成本”三大核心优势,刷新了全球开源模型的竞争格局。Qwen3在多项评测中超越DeepSeek-R…...
5. 配置舵机ID(具身智能机器人套件)
1. 连接舵机 waveshare驱动器板使用9-12v供电Type-C连接电脑DVG连接一个舵机 2. 使用FT SCServo Debug软件 设置串口设置波特率(默认1000000,100万)打开串口编程界面修改ID 3. 依次修改所有舵机ID 分别使用waveshare驱动板连接舵机&…...
Nacos源码—2.Nacos服务注册发现分析四
大纲 5.服务发现—服务之间的调用请求链路分析 6.服务端如何维护不健康的微服务实例 7.服务下线时涉及的处理 8.服务注册发现总结 7.服务下线时涉及的处理 (1)Nacos客户端服务下线的源码 (2)Nacos服务端处理服务下线的源码 (3)Nacos服务端发送服务变动事件给客户端的源码…...
从Windows开发迁移到信创开发的指南:国产替代背景下的技术路径与实践
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...
从数据到决策:安科瑞EIoT如何让每一度电“清晰可见”?
安科瑞顾强 在能源管理迈向精细化与数字化的今天,安科瑞EIoT能源物联网平台以“数据驱动能源价值”为核心理念,融合物联网、云计算与大数据技术,打通从设备感知到云端决策的全链路闭环,助力工商业企业、园区、物业等场景实现用电…...
10.学习笔记-MyBatisPlus(P105-P110)
1.MyBatisPlus入门案例 (1)MyBatisPlus(简称Mp)是基于MyBatis框架基础上开发的增强型工具,目的是简化开发,提高效率。 (2)开发方式:基于MyBatis使用MyBatisPlusÿ…...
LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding
TL;DR 2024 年 Meta FAIR 提出了 LayerSkip,这是一种端到端的解决方案,用于加速大语言模型(LLMs)的推理过程 Paper name LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding Paper Reading Note Paper…...
fastapi和flaskapi有什么区别
FastAPI 和 Flask 都是 Python 的 Web 框架,但设计目标和功能特性有显著差异。以下是它们的核心区别: 1. 性能与异步支持 FastAPI 基于 Starlette(高性能异步框架)和 Pydantic(数据校验库)…...
在 JMeter 中使用 BeanShell 获取 HTTP 请求体中的 JSON 数据
在 JMeter 中,您可以使用 BeanShell 处理器来获取 HTTP 请求体中的 JSON 数据。以下是几种方法: 方法一:使用前置处理器获取请求体 如果您需要在发送请求前访问请求体: 添加一个 BeanShell PreProcessor 到您的 HTTP 请求采样器…...
Go 1.25为什么要废除核心类型
关于核心类型为什么要1.25里要移除,作者Robert在博客Goodbye core types - Hello Go as we know and love it!里给了详细耐心的解答。 背景:Go 1.18 引入了泛型(generics),带来了类型参数…...
flask中的Response 如何使用?
在 Flask 中,Response 对象用于生成 HTTP 响应并返回给客户端。以下是其常见用法及示例: 1. 直接返回字符串或 HTML 视图函数返回的字符串会被自动包装为 Response 对象,默认状态码为 200,内容类型为 text/html: app…...
基于SpringAI实现简易聊天对话
简介 本文旨在记录学习和实践 Spring AI Alibaba 提供的 ChatClient 组件的过程。ChatClient 是 Spring AI 中用于与大语言模型(LLM)进行交互的高级 API,它通过流畅(Fluent)的编程接口,极大地简化了构建聊天…...
STM32单片机入门学习——第49节: [15-2] 读写内部FLASH读取芯片ID
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.29 STM32开发板学习——第49节: [15-2] 读写内部FLASH&读取芯片ID 前言开发板说…...
第14讲:科研图表的导出与排版艺术——高质量 PDF、TIFF 输出与投稿规范全攻略!
目录 📘 前言:导出,不只是“保存”! 🎯 一、你需要掌握的导出目标 🖼️ 二、TIFF / PNG 导出规范(适用于投稿) 🧲 三、PDF 矢量图导出(排版首选) 🧩 四、强烈推荐组合:showtext + Cairo 🧷 五、多个图的组合导出技巧 🧪 六、特殊投稿需求处理 �…...
SRIO IP调试问题记录(ready信号不拉高情况)
问题:调试过程中遇到有时写入数据后数据不发送,并且ready信号在写入一定数据后一直拉低的情况(偶发,不是每次必然出现)。buf空间设置为16时,写入15包数据,写完第16包包头后,ready信号…...
使用DDR4控制器实现多通道数据读写(十)
一、本章概述 本章节对目前单通道的读写功能进项测试,主要验证读写的数据是否正确,并观察该工程可以存储的最大容量。通过空满信号进行读写测试,根据ila抓取fifo和ddr4全部满的时刻,可以观察到最大容量。再通过debug逻辑可以测试读…...
从 BERT 到 GPT:Encoder 的 “全局视野” 如何喂饱 Decoder 的 “逐词纠结”
当 Encoder 学会 “左顾右盼”:Decoder 如何凭 “单向记忆” 生成丝滑文本? 目录 当 Encoder 学会 “左顾右盼”:Decoder 如何凭 “单向记忆” 生成丝滑文本?引言一、Encoder vs Decoder:核心功能与基础架构对比1.1 本…...
探寻软件稳定性的奥秘
在软件开发的广袤领域中,软件的稳定性宛如基石,支撑着整个软件系统的运行与发展。《发布!软件的设计与部署》这本书的第一部分,对软件稳定性进行了深入且全面的剖析,为软件开发人员、架构师以及相关从业者们提供了极具…...
Reverse-WP记录9
前言 之前写的,一直没发,留个记录吧,万一哪天记录掉了起码在csdn有个念想 1.easyre1 32位无壳elf文件 shiftF12进入字符串,发现一串数字,双击进入 进入main函数 int __cdecl main(int argc, const char **argv, const…...
日常开发小Tips:后端返回带颜色的字段给前端
一般来说,展示给用户的字体格式,都是由前端控制,展现给用户; 但是当要表示某些字段的数据为异常数据,或者将一些关键信息以不同颜色的形式呈现给用户时,而前端又不好判断,那么就可以由后端来控…...
partition_pdf 和chunk_by_title 的区别
from unstructured.partition.pdf import partition_pdf from unstructured.chunking.title import chunk_by_titlepartition_pdf 和 chunk_by_title 初看有点像,都在"分块",但是它们的本质完全不一样。 先看它们核心区别 partition_pdfchun…...
JAVA-使用Apache POI导出数据到Excel,并把每条数据的图片打包成zip附件项
最近项目要实现一个功能,就是在导出报表的时候 ,要把每条数据的所有图片都要打包成zip附件在excel里一起导出。 1. 添加依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>…...
前端——CSS1
一,概述 CSS(Cascading Style Sheets)(级联样式表) css是一种样式表语言,为html标签修饰定义外观,分工不同 涉及:对网页的文字、背景、宽、高、布局进行修饰 分为内嵌样式表&…...
《AI大模型应知应会100篇》【精华】第40篇:长文本处理技巧:克服大模型的上下文长度限制
[精华]第40篇:长文本处理技巧:克服大模型的上下文长度限制 摘要 在大语言模型应用中处理超出其上下文窗口长度的长文本是一项挑战。本文面向初学者介绍长文本处理的常见难题,以及一系列有效策略和技巧,包括如何对文档进行合理分…...
开源模型应用落地-qwen模型小试-Qwen3-8B-快速体验(一)
一、前言 阿里云最新推出的 Qwen3-8B 大语言模型,作为国内首个集成“快思考”与“慢思考”能力的混合推理模型,凭借其 80 亿参数规模及 128K 超长上下文支持,正在重塑 AI 应用边界。该模型既可通过轻量化“快思考”实现低算力秒级响应,也能在复杂任务中激活深度推理模式,以…...
千问3(Qwen3)模型开源以及初体验
体验地址:百炼控制台 1 千问3模型:全球最强开源大模型震撼发布 2025年4月29日,阿里巴巴正式开源了新一代通义千问模型Qwen3(简称千问3),这一里程碑式的事件标志着中国开源大模型首次登顶全球性能榜首。千问…...
对 FormCalc 语言支持较好的 PDF 编辑软件综述
FormCalc是一种专为PDF表单计算设计的脚本语言,主要应用于Adobe生态及SAP相关工具。以下是对FormCalc支持较好的主流软件及其特点: 1. Adobe LiveCycle Designer 作为FormCalc的原生开发环境,LiveCycle Designer提供最佳支持: …...
20250429-李彦宏口中的MCP:AI时代的“万能接口“
目录 一、什么是MCP? 二、为什么需要MCP? 三、MCP的工作原理 3.1 核心架构 3.2 工作流程 四、MCP的应用场景 4.1 开发者工具集成 4.2 智能助手增强 4.3 企业应用集成 4.4 典型案例 五、MCP的技术特点 5.1 标准化接口 5.2 可扩展性设计 5.…...
汽车启动原理是什么?
好的!同学们,今天我们来讨论汽车的启动原理,重点分析其中的动力来源和摩擦力作用。我会结合物理概念,用尽量直观的方式讲解。 1. 汽车为什么会动?——动力的来源 汽车发动机(内燃机或电动机)工…...
LeetCode[347]前K个高频元素
思路: 使用小顶堆,最小的元素都出去了,省的就是大,高频的元素了,所以要维护一个小顶堆,使用map存元素高频变化,map存堆里,然后输出堆的东西就行了 代码: class Solution…...
《软件测试52讲》学习笔记:如何设计一个“好的“测试用例?
引言 在软件测试领域,设计高质量的测试用例是保证软件质量的关键。本文基于茹炳晟老师在《软件测试52讲》中关于测试用例设计的讲解,结合个人学习心得,系统总结如何设计一个"好的"测试用例。 一、什么是"好的"测试用例…...
【深度学习新浪潮】ISP芯片算法技术简介及关键技术分析
ISP芯片及其功能概述 ISP(Image Signal Processor)芯片作为现代影像系统的核心组件,负责对图像传感器输出的原始信号进行后期处理。ISP的主要功能包括线性纠正、噪声去除、坏点修复、色彩校正以及白平衡调整等,这些处理步骤对于提高图像质量和视觉效果至关重要。随着科技的…...
QtCreator Kits构建套件报错(红色、黄色感叹号)
鼠标移动上去,查看具体报错提示。 一.VS2022Qt5.14.2(MSVC2017) 环境VS2022Qt5.14.2(MSVC2017) 错误:Compilers produce code for different ABIs:x86-windows-msvc2005-pe-64bit,x86-windows-msvc2005-pe-32bit 错误࿱…...
天能资管(SkyAi):全球布局,领航资管新纪元
在全球化浪潮汹涌澎湃的今天,资管行业的竞争已不再是单一市场或区域的较量,而是跨越国界、融合全球资源的全面竞争。天能资管(SkyAi),作为卡塔尔投资局(Qatar Investment Authority,QIA)旗下的尖端科技品牌,正以其独特的全球视野和深远的战略眼光,积极布局资管赛道,力求在全球资…...
基于PHP的宠物用品商城
有需要请加文章底部Q哦 可远程调试 基于PHP的宠物用品商城 一 介绍 宠物用品商城系统基于原生PHP开发,数据库mysql,前端bootstrap,jquery.js等。系统角色分为用户和管理员。(附带参考文档) 技术栈:phpmysqlbootstrapphpstudyvsc…...
桂链:使用Fabric的测试网络
桂链是基于Hyperledger Fabric开源区块链框架扩展开发的区块链存证平台,是桂云网络(OSG)公司旗下企业供应链、流程审批等场景数字存证软件产品,与桂花流程引擎(Osmanthus)并列为桂云网络旗下的标准与可定制…...