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

iOS实际开发中使用数据驱动页面布局

引言

在实际的APP开发中,我们通常会首先根据设计团队提供的视觉设计UI来构建我们的应用页面。这些设计通常是最全面和理想化的状态,因为设计师并不需要考虑用户的实际操作和交互。然而,如果我们仅仅根据这些设计进行硬编码,会在应用上线后发现许多难以处理的问题。

例如,有些功能会根据用户的身份选择性地显示或隐藏,有些功能会根据审核状态展示不同的样式,还有一些功能可能会根据运营活动来展示或撤销。如果我们通过硬编码来实现这些需求,那么在隐藏和显示某个功能时,可能需要修改大量代码来重新布局,这将极大地增加开发和维护的复杂度。

数据驱动页面布局

我们可以采用数据驱动页面布局的方案,让页面中的元素更加灵活可控,同时也使页面功能更易于扩展和维护。

案例

“Me”页是一个非常典型的案例。通常,这个页面功能复杂,元素类型多样。当我们看到这个设计时,脑海中应该已经有了大概的布局方案。接下来,我们将分别使用硬编码和数据驱动布局来实现这个页面,并分析它们之间的区别。

硬编码 - 直观布局

首先我们来分析一下页面结构,由于下面是重复的列表,那么很自然的我们就想到使用UITableView来实现的它,那么页面页面大致可以分为三个部分:

  • 导航栏:绿色区域,这里包括了用户昵称和设置按钮。
  • 列表头:红色区域,这里面包括了用户基本信息,VIP标记,钱包入口。
  • 列表:蓝色区域,这里包括了Me页的所有小功能入口,比如等级,成就,榜单等等。

这么划分看起来合情合理,结构也很清晰,那我们接下来就来实现它,代码如下:

    /// 列表let tableView = UITableView(frame: .zero, style: .plain)override func viewDidLoad() {super.viewDidLoad()addNavigationBar()addTableView()addTableHeaderView()}// 设置导航栏func addNavigationBar() {addCustomNavigationBar()}// 设置列表func addTableView() {tableView.frame = CGRect(x: 0, y: cs_navigationBarHeight, width: CS_SCREENWIDTH, height: CS_SCREENHIGHT - cs_navigationBarHeight)tableView.delegate = selftableView.dataSource = selftableView.backgroundColor = .whitetableView.separatorStyle = .noneself.view.addSubview(tableView)}// 设置列表头func addTableHeaderView() {let headerView = PHMeHeaderView()headerView.frame = CGRect(x: 0, y: 0, width: CS_SCREENWIDTH, height: 450.0)tableView.tableHeaderView = headerView}

由于我们的重点在于页面的布局方案,这里面就不展示每个元素的具体实现细节了。

总之我们已经按照设计图高度还原了UI,接下来我们来处理一下点击事件:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {if indexPath.row == 0 {print("排行榜")} else if indexPath.row == 1 {print("个人资料")} else if indexPath.row == 2 {print("等级")} else if indexPath.row == 3 {print("邀请奖励")}.....}

好万事大吉了,看起来已经可以提测验收了,这时候产品突然告诉你,我们要在加一个“任务”到列表里面的第2个位置,这时候该怎么做呢?

似乎也还好,单就点击事件来说,我们只需要以此往下移动就可以了,修改后代码如下:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {if indexPath.row == 0 {print("排行榜")} else if indexPath.row == 1 {print("任务")} else if indexPath.row == 2 {print("个人资料")} else if indexPath.row == 3 {print("等级")} else if indexPath.row == 4 {print("邀请奖励")}...}

这时候运营又要插个“活动”在第3个位置,但是只有VIP用户才显示,那我们又需要修改渲染部分和点击部分,还是单就点击事件来说,修改后代码如下:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {if indexPath.row == 0 {print("排行榜")} else if indexPath.row == 1 {print("任务")} else {if isVip {if indexPath.row == 2 {print("活动列表")} else if indexPath.row == 3 {print("个人资料")} else if indexPath.row == 4 {print("等级")} else if indexPath.row  == 5{print("邀请奖励")}} else {if indexPath.row == 2 {print("个人资料")} else if indexPath.row == 3 {print("等级")} else if indexPath.row  == 4{print("邀请奖励")}}}}

哇,看起来有一点乱了,况且这还是只有一个条件,如果有多个元素需要多个条件来控制,那每次需要修改的代码可就有点吓人了。

同样地,如果红色区域的部分需要调整,那么列表头内部的元素布局也需要修改大量代码。显然,硬编码的方式虽然直观,但在面对复杂多变的需求时显得有些捉襟见肘。

数据驱动 - 灵活布局

下面我们就使用数据驱动页面布局的方式再来实现这个页面。首先我们把页面的结构重新分割一下,将它们分割成更多更小的元素。

  • 导航栏:蓝色区域部分,这里仍然是导航栏的保留区域。
  • 用户信息:绿色部分,这里面包含了用户的基本信息。
  • VIP:紫色部分,VIP入口。
  • 钱包:橙色部分,钱包入口。
  • 其它列表:红色部分,其它样式相同但功能不同的入口。

这样分割之后呢,我们就只需要关注导航栏和列表就可以了,导航栏的UI已经固定且已经是最小元素,应该没有不会有什么变化,那么我们就把重点放到列表上。

每一个不同的区域都是一种类型的列表元素,那我们需要提前将所有的列表类型进行注册,代码如下:

    // 设置列表func addTableView() {tableView.frame = CGRect(x: 0, y: cs_navigationBarHeight, width: CS_SCREENWIDTH, height: CS_SCREENHIGHT - cs_navigationBarHeight)tableView.delegate = selftableView.dataSource = selftableView.backgroundColor = .whitetableView.separatorStyle = .noneself.view.addSubview(tableView)// 注册个人信息tableView.register(CSMeUserInfoCell.self, forCellReuseIdentifier: MeCellType.userInfo.rawValue)// 注册viptableView.register(CSMeVipCell.self, forCellReuseIdentifier: MeCellType.vip.rawValue)// 注册钱包tableView.register(CSMeWalletCell.self, forCellReuseIdentifier: MeCellType.wallet.rawValue)// 普通列表tableView.register(CSMeNormalCell.self, forCellReuseIdentifier: MeCellType.normal.rawValue)}

这样列表内所有元素的样式就都已经注册完成了,接下来我们开始处理数据。

首先继承自NSObject创建一个数据模型CSMeRowItemModel,代码如下:

class CSMeRowItemModel: NSObject {/// 标题var title:String?/// 图标var icon:UIImage?/// cellvar reuseIdentifier:String?/// 点击回调var clickBlock:(()->Void)?
}

该类里面有两个重要的数据 reuseIdentifier,列表cell的标识符,以及clickBlock一个闭包。

为了一步到位的介绍数据驱动布局的方式,我这里直接采用了分组的方式,因此还需要创建一个名为CSMeSectionItemModel的类,表示每组的数据,代码如下:

class CSMeSectionItemModel: NSObject {/// 子数据var subArray:[CSMeRowItemModel] = []/// 是否显示组标题var showSectionHeader:Bool = false
}

该类里面有一个主要数据就是subArray,里面保存了该组的item数据。

有了数据模型之后我们就可以开始构建数据列表了,为此我专门创建了一个CSMeConfigBuilder用来生成列表的页面数据。

生成Me页配置代码如下:

    /// 生成me页配置func buildMeConfig() -> [CSMeSectionItemModel] {var meConfig = [CSMeSectionItemModel]()// 个人信息let profileItem = buildProfileItem()meConfig.append(profileItem)// viplet vipItem = buildVipItem()meConfig.append(vipItem)// 钱包let walletItem = buildWalletItem()meConfig.append(walletItem)// 第一组let oneSectionItem = buildNormalOneSectionItem()meConfig.append(oneSectionItem)// 第二组
//        let twoSectionItem = buildNormalTwoSectionItem()
//        meConfig.append(twoSectionItem)
//        return meConfig}

而构建item列表的方法都大同小异,我就来列举两个吧,

构建钱包item,代码如下:

    // 生成钱包func buildWalletItem() -> CSMeSectionItemModel {let sectionItemModel = CSMeSectionItemModel()let walletItemModel = CSMeRowItemModel()walletItemModel.reuseIdentifier = MeCellType.wallet.rawValuewalletItemModel.clickBlock = {// 钱包CSRouter.shared.route(path: CSRouterUrlMeWalletRecharge)
//            CSRouter.shared.route(path: CSRouterUrlShortVideoWallet)}sectionItemModel.subArray.append(walletItemModel)return sectionItemModel}

构建通用样式item,代码如下:

    // 第一组func buildNormalOneSectionItem() -> CSMeSectionItemModel {let sectionItemModel = CSMeSectionItemModel()// 排行榜let rankItemModel = CSMeRowItemModel()rankItemModel.reuseIdentifier = MeCellType.normal.rawValuerankItemModel.title = "Ranking"rankItemModel.icon = UIImage(named: "me_item_ranking_icon")rankItemModel.clickBlock = { // 检查 是否是游客登录if CSTouristHelper.shared.checkTouristLogin(loginSuccess: nil) {return}// 跳转排行榜CSRouter.shared.route(path: CSRouterUrlHomeRank)}sectionItemModel.subArray.append(rankItemModel)// 个人信息let personalInfoItemModel = CSMeRowItemModel()personalInfoItemModel.reuseIdentifier = MeCellType.normal.rawValuepersonalInfoItemModel.title = "Personal Information"personalInfoItemModel.icon = UIImage(named: "me_item_personal_info_icon")personalInfoItemModel.clickBlock = {// 个人页guard let uid = CSAccountManager.shared.account?.user?.id else { return }var params = [String:Any]()params["uid"] = uidCSRouter.shared.route(path: CSRouterUrlMeProfile,params: params)}sectionItemModel.subArray.append(personalInfoItemModel)// 等级let levelItemModel = CSMeRowItemModel()levelItemModel.reuseIdentifier = MeCellType.normal.rawValuelevelItemModel.title = "Level"levelItemModel.icon = UIImage(named: "me_item_level_icon")levelItemModel.clickBlock = {//等级CSRouter.shared.route(path: CSRouterUrlMeLevel)}sectionItemModel.subArray.append(levelItemModel)// 邀请奖励let inviteItemModel = CSMeRowItemModel()inviteItemModel.reuseIdentifier = MeCellType.normal.rawValueinviteItemModel.title = "Rewards Invite"inviteItemModel.icon = UIImage(named: "me_item_invite_icon")inviteItemModel.clickBlock = {//邀请CSRouter.shared.route(path: CSRouterUrlMeInvite)}sectionItemModel.subArray.append(inviteItemModel)....return  sectionItemModel
}

接下来在页面控制器内我们只需要读取配置列表,使用列表数据直接渲染列表。

读取配置列表:

    /// 配置let configBuiler = CSMeConfigBuilder()/// 配置列表var configList = [CSMeSectionItemModel]()func initData() {configList = configBuiler.buildMeConfig()}

使用列表数据渲染UI:

    func numberOfSections(in tableView: UITableView) -> Int {return configList.count}func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {if section >= configList.count {CSAssert(false, "CSMeViewController section >= configList.count")return 0}let sectionItemModel = configList[section]return sectionItemModel.subArray.count}
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {let sectionItemModel = configList[indexPath.section]let itemModel = sectionItemModel.subArray[indexPath.row]let cell = tableView.dequeueReusableCell(withIdentifier: itemModel.reuseIdentifier!, for: indexPath)cell.selectionStyle = .none// 个人信息if let userInfoCell = cell as? CSMeUserInfoCell {userInfoCell.renderUserInfo()}// 普通cellif let normalCell = cell as? CSMeNormalCell {normalCell.renderData(itemModel)}return cell}

只需要这样做,页面就会根据我们配置好的数据渲染出来了。接下来就是处理点击事件,这就更容易了,因为我们已经把事件和数据绑定到了一起,我们只需要获取对应的数据,然后来调用它的闭包,代码如下:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {let sectionItemModel = configList[indexPath.section]let itemModel = sectionItemModel.subArray[indexPath.row]itemModel.clickBlock?()}

我们不需要添加任何判断,就可以把点击事件对应到我们想要的功能。

而且当页面需要添加元素,或者隐藏元素,哪怕是动态的显示和隐藏元素,我们都只需要操作CSMeConfigBuilder里面构建生成页面数据的方法,而不需要修改任何UI,除非是增加新的样式。

结语

通过这个典型的“Me”页案例,我们分别使用硬编码和数据驱动布局来实现页面构建。通过对比可以发现,在实际开发过程中,使用数据驱动页面布局的方式更加灵活且更容易扩展。每一个小元素都拥有完整的功能,在添加或删除时,我们只需要对数据略微进行修改,而不需要大幅度修改约束代码或添加大量的条件判断。这不仅提高了开发效率,也增强了代码的可维护性。

相关文章:

iOS实际开发中使用数据驱动页面布局

引言 在实际的APP开发中,我们通常会首先根据设计团队提供的视觉设计UI来构建我们的应用页面。这些设计通常是最全面和理想化的状态,因为设计师并不需要考虑用户的实际操作和交互。然而,如果我们仅仅根据这些设计进行硬编码,会在应…...

后端开发刷题 | 笔试

Linux 中,下面哪个选项不是 inode 中记录的数据() A 最后一次读取时间 B 最近修改的时间 C 该文件的实际内容 D 该文件的容量 正确答案:C 解析:储存文件的元信息,比如文件的创建者、文件的创建日期、文件的…...

ROS2入门到精通—— 2-8 ROS2实战:机器人安全通过狭窄区域的方案

0 前言 室内机器人需要具备适应性和灵活性,以便在狭窄的空间中进行安全、高效的导航。本文提供一些让机器人在狭窄区域安全通过的思路,希望帮助读者根据实际开发适当调整和扩展 1 Voronoi图 Voronoi图:根据给定的一组“种子点”&#xff0…...

STM32自己从零开始实操10:PCB全过程

一、PCB总体分布 分布主要参考有: 方便供电布线。方便布信号线。方便接口。人体工学。 以下只能让大家看到各个模块大致分布在板子的哪一块,只能说每个人画都有自己的理由,我的理由如下。 还有很多没有表达出来的东西,我也不知…...

折线图时间统计

1、查询本月的数据 2、查询最近一个月数据 1、查询本月数据 Date startTime DateUtil.getStartDayOfMonth();Date endTime DateUtil.getEndDayOfMonth();//获取日期//[2024-07-01, 2024-07-02, 2024-07-03, 2024-07-04, 2024-07-05, 2024-07-06, 2024-07-07, 2024-07-08, 20…...

Prompt工程:与AI聊天机器人更好地交流

Prompt工程:与AI聊天机器人更好地交流 1. 清楚地说明你想要什么2. 告诉AI它现在是谁3. 一步一步来4. 给AI一些例子5. 让AI检查自己的回答6. 把AI当作你的小助手7. 让AI帮你想主意8. 让AI告诉你它需要知道什么9. 教AI一步一步思考结语 大家好!今天我们来聊聊如何跟AI聊天机器人更…...

BGP之选路MED

原理概述 当一台BGP路由器中存在多条去往同一目标网络的BGP路由时,BGP协议会对这些BGP路由的属性进行比较,以确定去往该目标网络的最优BGP路由。BGP路由属性的比较顺序为Preferred Value属性、Local Preference属性、路由生成方式、AS_Path属性、Origin属…...

KunDB4.0:安全能力与Oracle兼容性提升,支持跨系统多租户部署

KunDB是星环科技自主研发的分布式交易型数据库,高度兼容Oracle和MySQL,提供数据强一致、高可用、高性能、高扩展、应用透明等能力,可在云上和物理机上容器化部署运行,一站式解决企业数据存储、管理、计算与安全性问题。 过去半年…...

JVM的 6 种垃圾回收算法

JVM的垃圾回收(Garbage Collection, GC)算法,在面试八股文时偶尔会被问到,了解一些常见的垃圾回收算法有利于面试时吊打面试官。 以下是JVM常见的几种垃圾回收算法的介绍: 1. 标记-清除算法(Mark-Sweep&a…...

【SOC 芯片设计 DFT 学习专栏 -- DFT OCC 与 ATPG的介绍】

请阅读【嵌入式及芯片开发学必备专栏】 请阅读【芯片设计 DFT 学习系列 】 如有侵权,请联系删除 转自: 简矽芯学堂 简矽芯学堂 2024年01月18日 09:00 陕西 文章目录 OCC 介绍Fast ScanFull chip ATPGPartition ATPGHierarchical ATPG OCC 介绍 OCC&am…...

自动驾驶-机器人-slam-定位面经和面试知识系列03之C++STL面试题(01)

这两天有点忙耽搁了,抱歉!!! 这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新,基本涵盖了自己秋招历程被问过的面试内容(除了实习和学校项目相关的具体细节)。…...

红狮金业解读:分析高价位黄金的后续投资吸引力

在全球经济格局不断变化的背景下,黄金作为传统的避险资产一直备受投资者关注。近期,金价持续走高,引发了市场对黄金是否仍然是优质资产配置的讨论。本文红狮启富将从长期需求、价格驱动因素的变化以及汇率影响三个角度,深入分析黄…...

LDR6020双盲插便携显示器应用

随着USB Type-C接口的普及,越来越多的手机和笔记本电脑都支持通过C接口输出视频。这个小巧而精密的接口,大有把传统的HDMI和DisplayPort接口取而代之的架势。特别是usb4的推出,更是为USB TYPE-C接口一统有线接口形态奠定了基础。 单USB-C接口…...

【HashMap源码学习】

HashMap的底层结构 HashMap是基于分离链表法解决散列冲突的动态散列表。 1、在jdk7中,使用的是“数组 链表”,发生散列冲突的时候键值对会用头插法添加到单链表中; 2、在jdk8中,使用的是“数组 链表 红黑树”,发…...

Git关联本地仓库和远程仓库

Step 1 添加远程仓库: git remote add <远程仓库别名><远程仓库地址> Step 2 git push -u <远程仓库名><分支名> 查看远程仓库: git remote -v 拉取远程仓库内容: 拉取服务器仓库过程中&#xff0c;如果本地和服务器有文件冲突&#xff0c;则会拉取失…...

【Django】在vscode中新建Django应用并新增路由

文章目录 打开一个终端输入新建app命令在app下的views.py内写一个视图app路由引入该视图项目路由引入app路由项目(settings.py)引入app&#xff08;AntappConfig配置类&#xff09;运行项目 打开一个终端 输入新建app命令 python manage.py startapp antapp在app下的views.py内…...

DT浏览器首页征集收录海内外网址

DT浏览器首页征集收录海内外网址&#xff0c;要求页面整洁&#xff0c;内容丰富&#xff0c;知识性和可读性强&#xff0c;符合大众价值观&#xff0c;不含恶意代码...

便携解码耳放

想象一下&#xff0c;你正在拥挤的地铁上&#xff0c;耳机里传来的音乐却仿佛带你置身于音乐厅&#xff0c;每一个音符都清晰、动人。这不是科幻小说&#xff0c;而是便携解码耳放&#xff08;DAC/AMP&#xff09;带给你的真实体验。无论你是在旅行、通勤还是在咖啡馆里工作&am…...

响应式编程框架Reactor之 Flux 和 Mono 的介绍和区别

Flux和Mono在Reactor框架中都是响应式编程模型的重要概念,它们在处理异步数据流时发挥着重要作用,两者之间也存在一些差异。 Mono的介绍 基本概念: Mono是Reactor中的一个类,它表示一个异步的单个值或零个值的结果。Mono可以看作是一个特殊的Publisher,用于产生数据流,…...

2.3 openCv 对矩阵执行掩码操作

在矩阵上进行掩模操作相当简单。其基本思想是根据一个掩模矩阵(也称为核)来重新计算图像中每个像素的值。这个掩模矩阵包含的值决定了邻近像素(以及当前像素本身)对新的像素值产生多少影响。从数学角度来看,我们使用指定的值来做一个加权平均。 具体而言,掩模操作通常涉…...

贪心算法(三) ---cmp_to_key, 力扣452,力扣179

目录 cmp_to_key 比较函数 键函数 cmp_to_key 的作用 使用 cmp_to_key 代码解释 力扣452 ---射气球 题目 分析 代码 力扣179 ---最大数 题目 分析 代码 cmp_to_key 在Python中&#xff0c;cmp_to_key 是一个函数&#xff0c;它将一个比较函数转换成一个键函数…...

学生信息管理系统详细设计文档

一、设计概述 学生信息管理系统是一个用于管理学生信息的软件系统&#xff0c;旨在提高学校对学生信息的管理效率。本系统主要包括学生信息管理、课程信息管理、成绩信息管理、班级信息管理等功能模块。详细设计阶段的目标是确定各个模块的实现算法&#xff0c;并精确地表达这…...

leetcode10 -- 正则表达式匹配

题目描述&#xff1a; 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s的&#xff0c;而不是部分字符串。 示例 1&#xff1…...

Binius-based zkVM:为Polygon AggLayer开发、FPGA加速的zkVM

1. 引言 近日&#xff0c;ZK硬件加速巨头Irreducible和Polygon团队宣布联合开发生产级的Binius-based zkVM&#xff0c;用于助力Polygon AggLayer&#xff0c;实现具有低开销、硬件加速的binary proofs。 Irreducible&#xff08;曾用名为Ulvetanna&#xff09;团队 Benjamin …...

基于 HTML+ECharts 实现的大数据可视化平台模板(含源码)

构建大数据可视化平台模板&#xff1a;基于 HTML 和 ECharts 的实现 大数据的可视化对于企业决策、市场分析和业务洞察至关重要。通过直观的数据展示&#xff0c;团队可以快速理解复杂的数据模式&#xff0c;发现潜在的业务机会。本文将详细介绍如何利用 HTML 和 ECharts 实现一…...

特征工程在机器学习中的重要性

特征工程在机器学习中的重要性 特征工程在机器学习中占据着至关重要的地位&#xff0c;它是连接原始数据与机器学习模型之间的桥梁。通过特征工程&#xff0c;我们可以将原始数据转换为机器学习算法能够有效利用的形式&#xff0c;从而提高模型的性能和准确性。以下是特征工程…...

【css】flex布局父元素宽度或高度无法被子元素撑开-bug记录

简言 flex布局父元素宽度或高度无法被子元素撑开问题。 解决方案&#xff1a; 手动计算子元素内容所占宽高&#xff0c;手动赋值给父元素即可。 flex布局宽高度问题 flex布局现在是特别常见得布局方式。 在此记录一个注意点&#xff1a;flex布局在不换行得情况下&#xff0c…...

Music Tag Editor Pro for Mac:强大的音频标签管理工具

Music Tag Editor Pro for Mac是一款专为Mac系统设计的音频标签管理工具&#xff0c;其简易直观的操作界面和强大的功能深受用户喜爱。 这款软件的核心功能在于它能够批量编辑各类音频文件的标签。无论是修改元数据、重命名文件&#xff0c;还是转换音乐标签的文本编码&#x…...

2024秋招算法

文章目录 参考资料一 数组1.1 二分查找1.2 移除元素1.3 长度最小的子数组1.4 螺旋矩阵1.5 在排序数组中查找元素的第一个和最后一个位置 二 链表2.1 移除链表元素2.2 设计链表2.3 反转链表2.4 两两交换链表中的节点2.5 删除链表的倒数第N个节点2.6 链表相交2.7 环形链表II 三 哈…...

El-Table 表格的表头字段切换

最近写了一个小功能&#xff0c;比较有意思&#xff0c;特此博客记录。 提出需求&#xff1a;需要表头字段变化&#xff0c;但是我在官网上的表格相关上查找&#xff0c;没有发现便捷方法。 于是我有两个想法&#xff1a;1.做三个不同的表格。2.做一个表格使用不同的表头字段。…...

分布式事务 详解

1.简介 2.本地事务失效问题 可以使用AOP starter aspectJ 代理 这样就可以拿到它的上下文的代理对象&#xff0c;当然是有这样的需求才这么做 如果你的事务只是想默认的传播行为&#xff0c;共用上面的事务&#xff0c;就可以不用这个啦 详情请去了解 Raft 算法 还有 pa…...

【git】太大了失败: fatal: fetch-pack: invalid index-pack output

#‘’ Git仓库过大致使clone失败的解决方法 上述大神的方法&#xff0c;亲测有效 中途失败: 太大了 fetch-pack: unexpected disconnect while reading sideband packet fatal: early EOF fatal: fetch-pack: invalid index-pack output关闭压缩 git config --global core.…...

在 ArchLinux 上编译运行 axmol 引擎

本文将在 Windows 10 上安装 Arch WSL 中编译 axmol 请确保 WSL2 已正确安装 1. 在微软应用商店安装 ArchLinux 2. 打开 Arch&#xff0c;按照提示输入用户名和密码&#xff0c;尽量简单 3. 配置清华源&#xff0c;速度快的起飞&#xff0c;否则&#xff0c;各种包会安装失败…...

云计算的三种服务模式

云计算的三种主要服务模式分别是基础设施即服务&#xff08;IaaS&#xff09;、平台即服务&#xff08;PaaS&#xff09;和软件即服务&#xff08;SaaS&#xff09;。每种服务模式都提供不同级别的抽象和管理&#xff0c;满足不同的需求和用例。以下是对这三种服务模式的详细介…...

Pytorch使用教学1-Tensor的创建

0 导读 在我们不知道什么是深度学习计算框架时&#xff0c;我们可以把PyTorch看做是Python的第三方库&#xff0c;在PyTorch中定义了适用于深度学习的张量Tensor&#xff0c;以及张量的各类计算。就相当于NumPy中定义的Array和对应的科学计算方法&#xff0c;正是这些基本数据…...

R语言统计分析——数据管理4

参考资料&#xff1a;R语言实战【第2版】 1、数学函数 abs(x)&#xff1a;绝对值 sqrt(x)&#xff1a;平方根 ceiling(x)&#xff1a;不小于x的最小整数 floor(x)&#xff1a;不大于x的最大整数 trunc(x)&#xff1a;向0的方向截取x中的整数部分 round(x,digitsn)&#…...

用uniapp 及socket.io做一个简单聊天app 2

在这里只有群聊&#xff0c;二个好友聊天&#xff0c;可以认为是建了一个二人的群聊。 const express require(express); const http require(http); const socketIo require(socket.io); const cors require(cors); // 引入 cors 中间件const app express(); const serv…...

Si24R03:高度集成的低功耗SOC芯片中文资料

Si24R03是一款高度集成的低功耗SOC芯片&#xff0c;具有低功耗、Low Pin Count、宽电压工作范围&#xff0c;集成了13/14/15/16位精度的 ADC、LVD、UART、SPI、I2C、TIMER、WUP、IWDG、RTC、无线收发器等丰富的外设。 合封说明&#xff1a;Si24R03为CSM32RV003和Si24R1的合封芯…...

K8s-控制器

一 为什么使用控制器 pod控制器 作用&#xff1a;1.pod类型资源删除&#xff0c;不会重建 2.控制器可以帮助用户监控&#xff0c;并保证节点上运行定义好的pod副本数 3.pod超过或低于用户期望&#xff0c;控制器会创建、删除pod副本数量 控制器类型&am…...

Meta 发布 LLAMA 3.1;特斯拉无人出租车推迟至 10 月;谷歌将向 Waymo 再投 50 亿美元

先瞧一下 Chat 和 Agent 的差异。 Chat&#xff08;聊天&#xff09;&#xff1a;纯粹的 Chat&#xff0c;宛如一个主要由“大脑与嘴”组成的智能体&#xff0c;着重于信息处置和语言沟通。诸如 ChatGPT 这般的系统&#xff0c;其能够领会用户的询问&#xff0c;给出有益且连贯…...

C 语言基础概念总结

C 语言基础概念总结 一、数据类型 目录 C 语言基础概念总结 一、数据类型 基本数据类型 构造数据类型 二、变量与常量 三、运算符与表达式 算术运算符 关系运算符 逻辑运算符 赋值运算符 自增自减运算符 四、控制流语句 顺序结构 选择结构 循环结构 五、函数 …...

Django教程(000):初识Django

Django 是一个高级 Python Web 框架,旨在快速开发、简洁、实用。Django 提供了众多内置功能,使得开发者可以专注于编写应用程序的业务逻辑,而不需要过多关注底层细节。以下是 Django 的详细介绍: 1. Django 简介 Django 是一个开放源代码的 Web 框架,由 Python 编写,最…...

SQLynx数据库管理工具

背景&#xff1a;业主对网络安全要求比较高&#xff0c;不提供VPN等远程工具&#xff0c;也不能开放3306端口到互联网。那怎么样运维数据库就是个难题&#xff1f;找到了SQLynx这个可以网页访问的数据库管理工具&#xff0c;给大家分享一下。 1.介绍 SQLynx原名SQL Studio&…...

Java基础06:变量,常量,作用域(狂神说Java)

一.变量 有了static&#xff0c;即类变量&#xff0c;就可以不用new了可以直接调用&#xff0c;类变量之后再细讲 二.常量 三.变量的命名规范...

inflight 守恒建模

去上海博物馆参观古埃及文物展&#xff0c;人太多&#xff0c;体验很差&#xff0c;我可以当讲解员的&#xff0c;但没人听&#xff0c;都只为拍照发圈。 平心而论&#xff0c;老家殷墟可与之一战&#xff0c;建议将殷墟交给国家运营&#xff0c;而不是一个地级市文旅。 无心…...

HarmonyOS NEXT星河版零基础入门到实战

文章目录 一、HarmonyOS NEXT介绍学习内容1、鸿蒙APP开发2、能力套件开发3、全场景开发适合人群 持续更新中✒️总结 一、HarmonyOS NEXT介绍 放弃安卓框架之后&#xff0c;HarmonyOS NEXT成为真正独立于安卓、iOS的操作系统&#xff0c;堪称是一场史无前例的脱胎换骨。在其众多…...

测试开发面试题---JVM

JAVA的内存区域 程序计数器&#xff1a;线程私有的&#xff0c;保存当前线程的字节码文件。JAVA虚拟机栈&#xff1a;包含局部变量信息&#xff0c;用于方法的调用和执行。本地方法栈&#xff1a;与JAVA虚拟机栈类似&#xff0c;但只服务于本地方法。堆&#xff1a;所有线程共…...

python库 - jsonpath

JSONPath 是一种用于从 JSON 数据中提取数据的查询语言&#xff0c;类似于 XML 中的 XPath。它允许通过路径表达式来导航和查询 JSON 结构中的数据。JSONPath 在处理 API 响应、配置文件和复杂数据结构时非常有用。 以下是一些常用的 JSONPath 表达式及其功能&#xff1a; $&…...

[RK3588][Android12] Android->OTA包超过4个G导致打包失败

测试平台 Platform: RK3588 OS: Android12 问题说明&#xff1a; 有的客户需要往系统中内置大量apk&#xff0c;这样就导致最终打包的OTA包超过4个G&#xff0c;从而导致打包OTA的时候报错&#xff1a;Zipfile size would require ZIP64 extensions 解决方法&#xff1a; 可能…...

(雷达数据处理中的)跟踪算法(3) – 可用于目标跟踪实践的数据集介绍解析

说明 本博文作为跟踪算法系列博文的第3篇&#xff0c;对可用于目标跟踪的一份数据集进行了介绍&#xff0c;本文介绍的这份数据集将用于后续博文的目标跟踪实践。读者在阅读本博文前&#xff0c;建议先看看本系列的第一篇博文[1]&#xff1a;&#xff08;雷达数据处理中的)跟踪…...