【iOS】UITableView性能优化

文章目录

  • 前言
  • 一、优化的本质
  • 二、卡顿产生原因
  • 三、CPU层面优化
    • 1.使用轻量级对象
    • 2.cellForRowAtIndexPath方法中不要做耗时操作
    • 3.UITableView的复用机制
    • 4.提前计算好布局
      • 了解tableView代理方法执行顺序
      • cell高度计算
        • rowHeight
        • estimatedRowHeight
      • 高度计算进行时机
        • rowHeight计算时机
        • estimatedRowHeight计算时机
      • 缓存cell高度
        • 实现原理
        • 实现方法
        • 实现代码
        • 缓存失效机制
      • 预缓存
    • 5.直接设置Frame
    • 6.异步绘制
    • 7.按需求加载
    • 8.异步加载图片:SDWebImage 的使用
  • 四、GPU层面优化
    • 离屏渲染
      • 1.引发离屏渲染的情况或操作
      • 2.圆角优化
      • 3.阴影优化
      • 4.优化建议
  • 总结


前言

最近基本将我的第二个项目完结,之后会记录一些源码的学习以及优化项目的一些方法,而在iOS中UITableView是最为常用的一种控件,今天我们就从UITableView性能优化开始讲起


一、优化的本质

UITableView 的优化本质在于提高滚动性能和减少内存使用,以保证流畅的用户体验,从计算机层面来讲,其核心本质为降低 CPU和GPU 的工作来提升性能

CPU:对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制
GPU:接收提交的纹理和顶点描述、应用变换、混合并渲染、输出到屏幕

二、卡顿产生原因

App主线程在CPU中显示计算内容,比如视图的创建,布局的计算,图片解码,文本绘制,然后我们的CPU会将计算好的内容提交到GPU中进行变换,合成,渲染,这其中也包括我们常说的离屏渲染

在开发中,CPUGPU任何一个压力过大都会导致掉帧

三、CPU层面优化

1.使用轻量级对象

在一些用不到事件处理的地方我们可以使用CALayer,而非UIViewCALayer相比于UIView更加接近底层

同时实际上每一个UIView都有一个CALayer的属性,其实我们可以把UIView理解为CALayer的高级封装,他们的本质区别在于是否能响应事件,这也是CALayer性能优于UIView的主要原因

CALayer 更接近于底层的渲染引擎。UIView 的渲染最终也是由底层的 CALayer 来完成的,但直接使用 CALayer 可以减少一些由于 UIView 带来的额外计算和抽象层次

_imageLayer = [CALayer layer];
_imageLayer.contentsGravity = kCAGravityResizeAspectFill;
_imageLayer.masksToBounds = YES;
// 假定图片大小为100x100,实际开发中应根据需要调整
_imageLayer.frame = CGRectMake((frame.size.width - 100) / 2, 20, 100, 100);
[self.layer addSublayer:_imageLayer];

2.cellForRowAtIndexPath方法中不要做耗时操作

我们这里的耗时操作包括:
1️⃣ 不读取文件 / 写入文件;
2️⃣ 尽量少用 addView 给 Cell 动态添加 View,可以初始化时就添加,然后通过 hide 来控制是否显示

因为我们在滑动我们的UITableView中会不断调用cellForRowAtIndexPath,这一点到后面会展开讲

3.UITableView的复用机制

这个部分属于是老生常谈了,简单来讲就是我们的UITableView只会创建比一个屏幕所有显示的cell+1个单元格,当当前的cell划出屏幕时,我们的cell并不会销毁,而是会将其存入我们的复用池

当要显示某一个位置的cell时首先会去复用池中查找,如果找不到才会重新创建,而不是每一次都进行重新创建,这样就极大地减少了内存开销

这里之前也写过博客总结,不再赘述
【iOS】自定义cell及其复用机制

4.提前计算好布局

了解tableView代理方法执行顺序

我们这里讲提前计算好布局的知识之前,我们需要先来了解一下tableView代理方法执行顺序
这一篇博客中有比较详细的介绍tableView代理方法执行顺序

如果我们设定了预估行高estimatedRowHeight,我们的Tableview会每一次先调用cellForRow又调一次对应的heightForRow方法

如果我们并没有设定estimatedRowHeight则会先遍历一次每个cell的tableView:heightForRowAtIndexPath:获取总的高度值 ,然后每调用一次cellForRow的时候再调用一次对应的heightForRow

但因为iOS11中的tableView的estimatedRowHeight默认值由原来的0变为UITableViewAutomaticDimension(打印出来为-1),因此我们可以大致认为我们每一次先调用cellForRow后会再调一次对应的heightForRow方法

也就是说我们的Tableview一定是先调用cellForRow方法,然后再调用heightForRow方法

cell高度计算

了解了这件事情与tableView的复用机制之后,我们再回头看我们的cellForRowheightForRow方法,我们知道当我们滑动tableview时就不断地调用这两个方法,因此这两个方法是性能优化的关键

UITableViewCell高度计算主要分为两种,一种固定高度,另外一种动态高度

rowHeight
self.tableView.rowHeight = 88;

这个属性是我们的固定高度,对于定高需求的表格,强烈建议使用这种方法来避免不必要的高度计算以及调用

另一种方式就是实现 UITableViewDelegate 中的:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {// return xxx
}

需要注意的是,实现了这个方法后,rowHeight 的设置将无效。所以,这个方法适用于具有多种 cell 高度的UITableView

estimatedRowHeight

这是一个估算行高的属性,对于动态计算行高,这里有多种方法,但核心还是通过设置预算高度和estimatedRowHeight = UITableViewAutomaticDimension,然后用AutoLayout对控件进行约束达到撑开cell的目的。

但是这也不可避免地加大了内存开销,因为AutoLayout最终需要转成frame

这里撑开cell达到动态计算行高在之前的博客中也有讲过,这里直接给链接【iOS】实现评论区展开效果

我们通过estimatedRowHeightAutoLayout大大简化了我们动态计算行高的过程,同时我们需要尽可能精确估计estimatedRowHeight的范围,即使面对种类不同的 cell,我们依然可以使用简单的 estimatedRowHeight 属性赋值,只要整体估算值接近就可以,比如大概有一半 cell 高度是 44, 一半 cell 高度是 88, 那就可以估算一个 66,基本符合预期。尽可能精确的估算可以使初次加载和滚动表格时更加流畅

高度计算进行时机

讲解完cell的两种高度计算方法,我们来分析一下这两种方法的计算时机

rowHeight计算时机

如果你为 UITableViewrowHeight 属性指定了一个具体的数值,那么所有的 cell 都将使用这个固定的高度,无需进行任何计算。

计算时机:在你设置 rowHeight 属性的时候或- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; 确定,之后不再进行计算。

estimatedRowHeight计算时机

当你实现了 UITableViewDelegate-tableView:heightForRowAtIndexPath: 方法并返回特定的高度值时,这个方法会在表格视图需要知道某个 cell 的高度时被调用

计算时机:有两个相关的阶段:
估算阶段:通过设置 estimatedRowHeight,UITableView 使用这个估算值来快速计算整个表格的滚动范围。这个估算值不需要精确匹配每个 cell 的实际高度,但应接近平均高度以优化性能。

self.pageTwoView.tableView.rowHeight = UITableViewAutomaticDimension;
self.pageTwoView.tableView.estimatedRowHeight = 200.0;

精确计算阶段:当 cell 即将显示在屏幕上时,UITableView 根据 Auto Layout 约束来计算 cell 的实际高度。这通常发生在滚动过程中,当新的 cell 即将进入可视区域时。

这个阶段通常发生在-tableView:heightForRowAtIndexPath:方法之后,tableView:willDisplayCell:forRowAtIndexPath:之前。

综上所述,cell的高度计算时机主要取决于如何设置UITableView 的行高策略

同时这里又引出了一个问题,如果我们在设置estimatedRowHeight后频繁滑动我们的Tableview,我们的heightForRowAtIndexPath方法就会不断被调用来计算我们的动态高度,这里又引出我们优化UITableview的一种新的思路,那就是缓存高度

缓存cell高度

我们在前面已经说到了我们cell高度的计算有两种方式:

  1. 直接通过rowHeight设置行高,避免不必要的高度计算。
  2. 通过Autolayout + estimatedRowHeight动态计算行高,这样可以使开发者更好去调整动态的cell的高度,但是这样就避免不了在滑动时对已经加载过的cell进行重复计算

我们是否可以通过一种方式可以让已经计算过的动态cell的高度不再重复计算,这就需要到我们的缓存高度

实现原理

存储每个 cell 的计算过的高度值,并在表格请求这些高度时重用这些值,而不是重新计算。

实现方法

首先我们要来回顾一下我们UITaleview协议的执行顺序

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
  2. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
  3. - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

这三个方法是按顺序执行的,我们的高度缓存以这三个方法展开

同时这里着重讲一下第三个方法,第三个方法调用的时候我们的cell已经配置完毕,因此我们可以直接在方法中得到cell高度进行缓存,缓存之后下一次再碰到相同的cell直接从我们的缓存中将高度取出来即可

实现代码
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {if (indexPath.section == 0) {return 140;} else {NSString *cacheKey = [NSString stringWithFormat:@"%ld-%ld", (long)indexPath.section, (long)indexPath.row];// 检查缓存NSNumber *cachedHeight = [self.heightCache objectForKey:cacheKey];if (cachedHeight) {NSLog(@"存在缓存%@", cacheKey);return cachedHeight.doubleValue;} else {// 缓存行高return UITableViewAutomaticDimension;}}
}

首先我们在heightForRowAtIndexPath代码中检查是否有缓存,如果没有我们则返回UITableViewAutomaticDimension来自动计算行高,有的话则返回cachedHeight.doubleValue来避免重新计算

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {CGFloat cellHeight = cell.frame.size.height;//添加缓存NSString *cacheKey = [NSString stringWithFormat:@"%ld-%ld", (long)indexPath.section, (long)indexPath.row];[self.heightCache setObject:@(cellHeight) forKey:cacheKey];
}

然后我们在willDisplayCell中获取行高并将其加入缓存,当我们滑动到已经加载过的cell时我们的heightForRowAtIndexPath方法就会先检查缓存中是否有已经存入的高度,从而避免了重新计算导致内存开销

缓存失效机制

当我们对我们的TableView添加数据时我们的缓存也会随之添加数据,这个方法十分容易实现
但是对于删除数据源时,这个就比较复杂了
当删除一个 indexPath 为 [0:5] 的 cell 时,要使[0:0] ~ [0:4] 的高度缓存不受影响,而 [0:5] 后面所有的缓存值都向前移动一个位置
这个方法是如何实现的在下方的库中有具体实现,后面看源码的时候会加以补充

预缓存

也许到了上面这一步有些人已经觉得优化地比较OK了,但是这里笔者再提出一个问题:
我们使用缓存高度这个方法时是否必须要将所有的cell都先遍历一遍,然后将其存入我们的缓存模型

如果仅仅按照上面的方法,这个问题是肯定的,因为没有呈现在屏幕上的cell并没有存入我们的缓存模型,当我们一个个滑动到对应cell时,对应的cell才逐步加入到缓存模型中

我们是否可以实现将没有呈现在屏幕上的cell也悄无声息地加入我们的缓存模型中呢

这里笔者在查阅资料时发现了一个第三方库很好地解决了这个问题,尽管这个库已经很久没有维护了,但是他其中涉及到RunLoop的思想十分适合学习
FDTemplateLayoutCell

在大佬的博客中,他们RunLoop空闲时间执行预缓存任务

其中说到:

FDTemplateLayoutCell
的高度预缓存是一个优化功能,它要求页面处于空闲状态时才执行计算,当用户正在滑动列表时显然不应该执行计算任务影响滑动体验。

也就是说当我们的页面静止时,我们可以对我们的高度进行预缓存,这样既不会影响用户的使用体验,也优化了UITableView的性能

因为笔者还未系统学习RunLoop,这里简单讲一些自己对这个库的实现原理的理解

  1. 注册RunLoopObserver来找准执行预缓存的时机
  2. 当RunLoop处于NSDefaultRunLoopMode的Mode时,也就是空闲状态时
  3. 同时当这一次 RunLoop 迭代处理完成了所有事件,马上要休眠时
    以上这三点同时实现后我们就可以开始执行预缓存

这里具体的实现在系统学习RunLoop之后会回头学习补充

5.直接设置Frame

对于比较简单的cell,不涉及到动态高度变化,我们可以直接通过Frame设置尺寸,因为使用AutoLayout或是Masonry进行布局时会消耗更多CPU资源去计算尺寸

6.异步绘制

就是异步在画布上绘制内容,将复杂的绘制过程放到后台线程执行,然后在主线程显示
在这里插入图片描述
这里的原理还没有了解,后面系统学习GCD等知识后回来补充
iOS-UIView异步绘制

7.按需求加载

(1)滑动操作时,只显示目标范围内的cell内容,显示过的超出目标范围内之后则进行清除;

核心思想:当用户滑动表格或集合视图时,只为屏幕范围内可见的单元格(cell)加载内容。一旦这些单元格滚动出屏幕变得不可见,与它们关联的资源(如图像数据)应该被清除或释放,以避免不必要的内存占用。

实现方法:利用 UITableViewUICollectionView 的代理方法来跟踪哪些单元格是可见的。当单元格即将出现在屏幕上时(例如在 tableView:willDisplayCell:forRowAtIndexPath: 方法中),加载并显示其内容
当单元格滑出屏幕变得不可见时(例如在tableView:didEndDisplayingCell:forRowAtIndexPath: 方法中),可以释放或清除这些单元格的额外资源

(2)滑动过程中,不加载显示图片,停止时才加载显示图片;
核心思想:当快速滚动时用户无法详细查看这些图片,这样就避免大量的资源加载与绘制操作,当停止滚动时才会加载显示在当前屏幕的图片

实现方法:通过监听 UIScrollViewDelegatescrollViewDidScroll: 和 scrollViewDidEndDecelerating: 方法来判断滚动状态。在 scrollViewDidScroll: 中暂停加载图片

scrollViewDidEndDecelerating:(滚动停止)和 scrollViewDidEndDragging:willDecelerate:(拖拽停止)方法中恢复加载。对于图片加载,可以使用异步加载和缓存机制,如使用第三方库 SDWebImage 或 Kingfisher 时,它们提供的 API 支持这种按需加载策略。

8.异步加载图片:SDWebImage 的使用

(1)使用异步子线程处理,然后再返回主线程操作;
(2)图片缓存处理,避免多次处理操作;
(3)图片圆角处理时,设置 layer 的 shouldRasterize 属性为 YES,可以将负载转移给 CPU;

第七部分与这一部分内容在学习玩SDWebImage的源码后会加以补充


四、GPU层面优化

离屏渲染

GPU主要负责渲染与绘制图形,因此在这个层面我们着重讲一下iOS中的离屏渲染对UITableView性能产生的影响

在OpenGL中,GPU对屏幕的渲染有以下两种方式:
On-Screen Rendering:意思是当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区进行
Off-Screen Rendering:意思就是我们说的离屏渲染了,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。

相比于当前屏幕渲染,离屏渲染的代价是很高的,主要体现在两个方面:

  1. 创建新缓冲区,要想进行离屏渲染,首先要创建一个新的缓冲区。
  2. 上下文切换,离屏渲染的整个过程,需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上有需要将上下文环境从离屏切换到当前屏幕。而上下文环境的切换是要付出很大代价的。

1.引发离屏渲染的情况或操作

光栅化:layer.shouldRasterize = YES

遮罩:layer.mask

圆角:同时设置 layer.masksToBounds = YES 和 layer.cornerRadius > 0

阴影:layer.shadowlayer.allowsGroupOpacity = YES 和 layer.opacity != 1

重写drawRect方法

2.圆角优化

使用贝塞尔曲线UIBezierPath和Core Graphics框架画出一个圆角

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
imageView.image = [UIImage imageNamed:@"myImg"]; 
//开始对imageView进行画图 
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0); 
//使用贝塞尔曲线画出一个圆形图
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:imageView.frame.size.width] addClip];
[imageView drawRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext(); 
//结束画图 
UIGraphicsEndImageContext();
[self.view addSubview:imageView]; 

3.阴影优化

对于shadow,如果图层是个简单的几何图形或者圆角图形,我们可以通过设置shadowPath来优化性能,能大幅提高性能

imageView.layer.shadowColor = [UIColor grayColor].CGColor;
imageView.layer.shadowOpacity = 1.0;
imageView.layer.shadowRadius = 2.0;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:imageView.frame];
imageView.layer.shadowPath = path.CGPath;

4.优化建议

  • 使用中间透明图片蒙上去达到圆角效果
  • 使用ShadowPath指定layer阴影效果路径
  • 使用异步进行layer渲染
  • 将UITableViewCell及其子视图的opaque属性设为YES,减少 - 复杂图层合成
  • 尽量使用不包含透明alpha通道的图片资源
  • 尽量设置layer的大小值为整形值
  • 背景色的alpha值应该为1,例如不要使用clearColor
  • 直接让美工把图片切成圆角进行显示,这是效率最高的一种方案
  • 很多情况下用户上传图片进行显示,可以让服务端处理圆角

离屏渲染这部分后面系统学习后会单开博客讲解,这里只讲个大概

总结

UITableView的性能优化涉及到了许多层面,下到底层的Layer属性,上到第三方库SDWebImage与RunLoop,这些东西的实现都十分巧妙,还有很长一段路需要学习

这里笔者写一下Tableview 性能优化方法总览

  • 实现Tableview的懒加载以及cell的复用(这是优化Tableview最基础的部分,老生常谈了,特别是复用池这一块的内容:将加载过的cell加入到复用池中,需要时取出)
  • 高度缓存(本篇文章着重介绍了cell的高度缓存机制,因为heightForRowAtIndexPath: 是调用最频繁的方法,我们围绕这个方法展开,通过避免重复计算来减少我们的内存开销。当行高固定时使用固定行高,不固定时缓存一次后返回固定行高)
  • 预缓存(在高度缓存的实现上进行优化,涉及到RunLoop层面的知识,后面加以补充,似乎与SDWebImage有异曲同工之处,十分巧妙)
  • 异步加载图片(SDWebImage的使用,后面看源码看完再回来总结)
  • 按需加载内容(涉及到许多协议,当快速滑动时不加载资源,即将停止滑动时加载资源,同时释放那些超出屏幕的资源,只显示目前呈现在屏幕上的内容)
  • 视图层面(避免离屏渲染,使用贝塞尔曲线或是直接呈现采裁剪后的圆角图片来避免离屏渲染的发生,另外还可以使用异步绘制来实现绘制图片,后面会专开博客讲解)

借鉴博客:
iOS tableView 优化
优化UITableViewCell高度计算的那些事
UITableView 优化
swift5.x tableViewCell自适应高度及高度缓存(systemLayoutSizeFitting)
iOS UITableView性能优化
iOS 保持界面流畅的技巧(转载)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/798624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring boot+Vue的业余排球俱乐部会员管理系统

5 系统功能模块的具体实现 5.1超级会员角色 5.1.1 登录 超级管理员登录通过用户名和密码去数据库查询用户表,该名称是否在用户表中存在,如果存在,则通过用户名和密码查询密码是否正确,然后吧用户的信息存在jwt的负载里&#xf…

【CicadaPlayer】demuxer_service的简单理解

G:\CDN\all_players\CicadaPlayer-github-0.44\mediaPlayer\SMPMessageControllerListener.cppplayer的demuxer服务类 std::unique_ptr<demuxer_service> mDemuxerService{nullptr};根据option (Cicada::options),可以决定音视频的不同操作,通过 hander可以获得具体使…

探究“大模型+机器人”的现状和未来

基础模型(Foundation Models)是近年来人工智能领域的重要突破&#xff0c;在自然语言处理和计算机视觉等领域取得了显著成果。将基础模型引入机器人学&#xff0c;有望从感知、决策和控制等方面提升机器人系统的性能&#xff0c;推动机器人学的发展。由斯坦福大学、普林斯顿大学…

Redis中的Sentinel(六)

Sentinel 选举领头Sentinel. 当一个主服务器被判断为客观下线时&#xff0c;监视这个下线主服务器的各个Sentinel会进行协商&#xff0c;选举出一个领头Sentinel,并由领头 Sentinel对下线主服务器执行故障转移操作。以下是Redis选举领头Sentinel的规则和方法: 1.所有在线的S…

大日志精选案例四:某省级大数据集团日志审计优化实战解析

“在集团日常运营中&#xff0c;数据安全始终是我们关注的重点。过去&#xff0c;数据量大、处理速度慢&#xff0c;导致日志数据难以迅速获取和分析&#xff0c;影响业务决策。但自从引入聚铭大日志解决方案后&#xff0c;系统日志和用户行为数据都得到了高效处理与存储。该方…

Nginx配置之localhost和反向代理

文章目录 第一步、查看安装位置和配置文件第二步、web服务器设置第三步、localhost 指令第四步、设置反向代理 清明假期&#xff0c;在家练习Nginx配置&#xff0c;在前期【 linux环境下安装配置nginx代理服务器】已经完成nginx环境搭建&#xff0c;本期主要实践web服务器&…

力扣刷题 102.二叉树的层序遍历

目录 题干 解题思路 总结与反思 题干 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9…

守护用户数据安全,共筑企业利益长城——遵循常州小程序安全防护指南

在数字化浪潮席卷各行各业的今天&#xff0c;小程序以其轻量化、便捷化的特点&#xff0c;成为连接企业和用户的桥梁&#xff0c;极大地提升了服务效率与用户体验。然而&#xff0c;随着用户数据价值日益凸显&#xff0c;小程序的安全防护工作显得尤为重要。常州小程序安全防护…

闲鱼订阅监控/上新提醒

以前闲鱼推出过一款服务&#xff0c;叫做闲鱼助手&#xff0c;帮助用户快速显示最新发布的信息。当时我也开发过一款闲鱼助手的工具。 写一个闲鱼助手的助手工具_闲鱼助手源码-CSDN博客 但是时间并不是很长&#xff0c;该功能被取消了。 最近不知道闲鱼从哪个版本开始&#x…

基于Python的自然语言的话题文本分类(V2.0),附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

具有温度系数(Temperature)的Softmax函数

Softmax 函数 softmax 函数是一种激活函数&#xff0c;通常用作神经网络最后一层的输出函数。该函数是两个以上变量的逻辑函数的推广。 Softmax 将实数向量作为输入&#xff0c;并将其归一化为概率分布。 softmax函数的输出是与输入具有相同维度的向量&#xff0c;每个元素的…

C语言程序与设计——指针地址与main函数

指针变量 在C语言中&#xff0c;最重要的就是对于指针和地址的理解&#xff0c;因为C语言是更接近底层的编程语言&#xff0c;所以它可以允许开发者对内存操作&#xff0c;这也是区别于其它编程语言的一个重要特性。 如何对内存进行操作呢。我们知道在编程过程中&#xff0c;在…

突破编程_前端_SVG(基础元素介绍)

1 rect 矩形 在 SVG 中&#xff0c;<rect> 元素用于创建圆形。 &#xff08;1&#xff09;基本语法 <rectx"x坐标"y"y坐标"width"宽度"height"高度"rx"可选&#xff1a;圆角x半径"ry"可选&#xff1a;圆角…

用可视化案例讲Rust编程5.用泛型和特性实现自适配绘制和颜色设置

上一节我们讲了用泛型实现返回结果&#xff0c;这一节我们来讲讲在函数签名里面使用泛型来对输入参数进行自适配。 先看UML设计图&#xff1a; 好吧&#xff0c;看起来有点复杂&#xff0c;我们一个个来解释。 首先定义的是一个生成绘图元素需要的参数结构,并且定义个特性&am…

Spring Security——09,解决跨域

解决跨域 一、SpringBoot配置二、配置SpringSecurity三、修改端口四、修改vue项目4.1 拿到token4.2 前端存储token4.3 前端请求头携带token 五、测试5.1 认证测试5.2 授权测试 一键三连有没有捏~~ 浏览器出于安全的考虑&#xff0c;使用 XMLHttpRequest对象发起 HTTP请求时必须…

day 74 js

js脚本 JS的作用&#xff1a; 描述显示的内容&#xff08;HTML&#xff09;修饰 HTML 标签&#xff08;CSS&#xff09;设置 HTML 标签的动作&#xff08;JS&#xff09;JS特点&#xff1a;基于对象的编程语言&#xff0c;通过浏览器解释执行作用&#xff1a;表单验证、改变标签…

使用阿里云服务器可以做什么?太多了

阿里云服务器可以干嘛&#xff1f;能干啥你还不知道么&#xff01;简单来讲可用来搭建网站、个人博客、企业官网、论坛、电子商务、AI、LLM大语言模型、测试环境等&#xff0c;阿里云百科aliyunbaike.com整理阿里云服务器的用途&#xff1a; 阿里云服务器活动 aliyunbaike.com…

AcWing 4. 多重背包问题 I

解题思路 相关思路 import java.util.Scanner; public class Main {public static void main(String[] args){Scanner scanner new Scanner(System.in);int N scanner.nextInt();int V scanner.nextInt();int v[] new int[N1];int w[] new int[N1];int s[] new int[N1];…

揭秘AI幻觉:GPT-4V存在视觉编码漏洞,清华联合NUS提出LLaVA-UHD

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 GPT-4V 的推出引爆了多模态大模型的研究。GPT-4V 在包括多模态问答、推理、交互在内的多个领…

二. CUDA编程入门-双线性插值计算

目录 前言0. 简述1. 执行一下我们的第十个CUDA程序2. Bilinear interpolation3. 代码分析总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 Note&#xff1a;关于 CUDA 加速双线程插值的内容博主…