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

深入解析iOS视频录制(二):自定义UI的实现

深入解析 iOS 视频录制(一):录制管理核心MWRecordingController 类的设计与实现

深入解析iOS视频录制(二):自定义UI的实现​​​​​​​

深入解析 iOS 视频录制(三):完整录制流程的实现与整合​​​​​​​

引言

在上一篇博客中,我们深入解析了 iOS 视频录制功能的核心类 MWRecordingController 的实现,涵盖了如何管理视频会话、设置输入输出、控制摄像头以及录制的启动与停止等重要功能。本篇博客将接着上文,探索自定义 UI 的实现,重点讲解如何通过 MWRecordingPreview 预览视图、MWRcordingControlView 控制视图以及精心设置的自定义按钮来提升视频录制的用户体验。

我们将逐步揭开这些自定义 UI 组件背后的设计与实现,了解如何通过灵活的视图布局与动画效果,让录制过程更加直观与流畅。希望通过本篇博客,能够帮助大家更深入地理解如何在 iOS 中定制出高质量的视频录制界面。

UI实现

在视频录制功能中,UI 设计不仅仅是视觉呈现,更是与用户交互的桥梁。一个直观、流畅且具有良好反馈的界面,能够大大提升用户的使用体验。通过自定义 UI,我们能够精细控制各个交互细节,确保用户能够快速而顺畅地完成录制操作。

本篇博客将从三个核心部分入手,详细讲解自定义 UI 的实现:

  1. 预览视图的实现:如何设计并展示视频录制的预览内容,确保录制时用户能够实时看到画面。
  2. 控制视图的实现:包括录制、暂停、重新录制以及完成按钮等,通过合理布局和状态管理,使得控制操作清晰易懂。
  3. 顶部导航栏视图的实现:导航栏中的返回按钮与切换摄像头按钮如何与视频录制功能进行无缝集成。

接下来,我们将逐一展开讲解这些关键视图的设计与实现,带大家了解如何通过代码构建一个高效且美观的视频录制界面。

MWRecordingPreview:预览视图的实现

MWRecordingPreview 类是整个视频录制界面中关键部分之一,它负责显示来自摄像头的实时视频预览。在本次实现中,我们简化了设计,确保预览层与录制会话紧密配合,并通过简单的配置来实现画面显示。

以下是 MWRecordingPreview 类的实现代码:

import UIKit
import AVFoundationclass MWRecordingPreview: UIView {override init(frame: CGRect) {super.init(frame: frame)previewLayer.videoGravity = .resizeAspectFill}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}override class var layerClass: AnyClass {return AVCaptureVideoPreviewLayer.self}/// 预览图层var previewLayer: AVCaptureVideoPreviewLayer {return layer as! AVCaptureVideoPreviewLayer}/// 设置图层会话var session:AVCaptureSession? {didSet {previewLayer.session = session}}
}
  1. layerClass:通过重写 layerClass 方法,我们指定了该视图的图层类型为 AVCaptureVideoPreviewLayer,这是一个专门用于显示摄像头预览内容的图层类。
  2. previewLayer:该属性返回类型为A VCaptureVideoPreviewLayer 的图层,我们可以通过它来访问与摄像头相关的配置。
  3. session:这个属性用来设置 AVCaptureSession,它是视频录制功能的核心,管理着输入输出设备以及数据流。通过 didSet 方法,当会话对象被设置时,预览层的 session 会自动与之绑定,从而实现实时预览功能。

通过这种简单的实现,我们就能将摄像头的实时图像呈现在自定义视图 MWRecordingPreview 中,并且具备了灵活的图像填充方式,使用 .resizeAspectFill 可以确保预览画面根据视图的大小自适应显示。

MWRecordingControlView:控制视图的实现

MWRecordingControlView 类负责管理视频录制过程汇总的交互空间,包括录制按钮、录制时间显示、重新录制按钮以及完成按钮。通过合理布局与状态管理,确保用户能够清晰地了解录制进度,并灵活地控制录制行为。

以下是 MWRecordingControlView 类的实现代码:

import UIKitenum MWRecordingControlState {/// 正常case normal/// 录制中case recording/// 录制完成case finish
}class MWRecordingControlView: UIView {/// 录制按钮private let recordButton = MWRecordingButton()/// 录制时间private let recordTimeLabel = UILabel()/// 重新录制按钮private let reRecordButton = MWRecordingItemButton()/// 完成按钮private let finishButton = MWRecordingItemButton()/// 录制按钮点击事件回调var recordButtonClickBlock: (() -> Void)?/// 重新录制点击回调var reRecordButtonClickBlock: (() -> Void)?/// 完成点击回调var finishButtonClickBlock: (() -> Void)?override init(frame: CGRect) {super.init(frame: frame)setupView()setLayout()setEvent()setRecordingState(state: .normal)}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setupView() {// 录制按钮addSubview(recordButton)// 录制时间addSubview(recordTimeLabel)recordTimeLabel.textColor = .whiterecordTimeLabel.font = MWFontHelper.font(name: .nunito, size: 14, weight: .bold)// 重新录制按钮addSubview(reRecordButton)reRecordButton.setImage(UIImage(named: "recording_retake"), for: .normal)reRecordButton.setTitle(MWLocaleStringHelper.getString("Retake"), for: .normal)reRecordButton.setTitleColor(.white, for: .normal)reRecordButton.titleLabel?.font = MWFontHelper.font(name: .nunito, size: 14, weight: .bold)reRecordButton.titleLabel?.textAlignment = .center// 完成按钮addSubview(finishButton)finishButton.setImage(UIImage(named: "recording_complete"), for: .normal)finishButton.setTitle(MWLocaleStringHelper.getString("Complete"), for: .normal)finishButton.setTitleColor(.white, for: .normal)finishButton.titleLabel?.font = MWFontHelper.font(name: .nunito, size: 14, weight: .bold)finishButton.titleLabel?.textAlignment = .center}private func setLayout() {// 录制按钮recordButton.snp.makeConstraints { make inmake.centerX.equalToSuperview()make.top.equalToSuperview()make.width.height.equalTo(72.0)}// 录制时间recordTimeLabel.snp.makeConstraints { make inmake.centerX.equalToSuperview()make.top.equalTo(recordButton.snp.bottom).offset(12.0)make.height.equalTo(19.0)}// 重新录制按钮reRecordButton.snp.makeConstraints { make inmake.trailing.equalTo(recordButton.snp.leading).offset(-44.0)make.width.equalTo(64.0)make.height.equalTo(63.0)make.centerY.equalTo(recordButton)}// 完成按钮finishButton.snp.makeConstraints { make inmake.leading.equalTo(recordButton.snp.trailing).offset(44.0)make.width.equalTo(64.0)make.height.equalTo(63.0)make.centerY.equalTo(recordButton)}}private func setEvent() {// 录制按钮recordButton.addTarget(self, action: #selector(recordButtonClick), for: .touchUpInside)// 重新录制按钮reRecordButton.addTarget(self, action: #selector(reRecordButtonClick), for: .touchUpInside)// 完成按钮finishButton.addTarget(self, action: #selector(finishButtonClick), for: .touchUpInside)}/// 录制事件@objc private func recordButtonClick() {recordButtonClickBlock?()}/// 重新录制事件@objc private func reRecordButtonClick() {reRecordButtonClickBlock?()}/// 完成事件@objc private func finishButtonClick() {finishButtonClickBlock?()}/// 设置录制状态/// - Parameter state: 状态func setRecordingState(state: MWRecordingControlState) {switch state {case .normal:recordButton.isSelected = truerecordTimeLabel.isHidden = truereRecordButton.isHidden = truefinishButton.isHidden = truecase .recording:recordButton.isSelected = falserecordTimeLabel.isHidden = falsereRecordButton.isHidden = truefinishButton.isHidden = truecase .finish:recordButton.isSelected = truerecordTimeLabel.isHidden = falsereRecordButton.isHidden = falsefinishButton.isHidden = false}}/// 更新时间/// - Parameter time: 时间func updateTime(time: TimeInterval) {recordTimeLabel.text = time.formattedMS}
}

MWRecordingControlView 提供了以下几个核心功能:

  1. 录制按钮(recordButton):用于控制录制的开始和暂停。根据状态变化,按钮的样式会自动调整。
  2. 录制时间(recordTimeLabel):显示当前录制的时长,动态更新。
  3. 重新录制按钮(reRecordButton):在录制完成后,允许用户重新开始录制。
  4. 完成按钮(finishButton):会在点击完成时,将录制好的音频文件传递到需要的地方。

通过设置不同的录制状态(normal、recording和finish),控制视图中的各个按钮和标签的显示与隐藏,确保用户能够清晰地看到当前操作的状态。

MWRecordingButton:录制按钮

MWRecordingButton 是自定义的录制按钮,通过多层图层效果展现录制状态,并使用CALayer和CAGradientLayer创建了独特的视觉效果。其设计目标是提供一个既美观又符合录制功能需求的按钮,用户可以通过点击它来启动或停止视频录制。

以下是 MWRecordingButton 类的实现代码:

import UIKitclass MWRecordingButton: UIButton {/// 大圆图层private let bigCircleLayer = CALayer()/// 小圆图层private let smallCircleLayer = CALayer()/// 方形图层private let squareLayer = CAGradientLayer()override init(frame: CGRect) {super.init(frame: frame)setupLayer()}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setupLayer() {// 大圆bigCircleLayer.backgroundColor = UIColor.white.withAlphaComponent(0.6).cgColorbigCircleLayer.cornerRadius = 36.0layer.addSublayer(bigCircleLayer)// 小圆smallCircleLayer.backgroundColor = UIColor.white.withAlphaComponent(1.0).cgColorsmallCircleLayer.cornerRadius = 30layer.addSublayer(smallCircleLayer)// 方形squareLayer.colors = [UIColor.wm_hex("FF3498").cgColor, UIColor.wm_hex("FF4545").cgColor]squareLayer.cornerRadius = 6.0layer.addSublayer(squareLayer)}override var isSelected: Bool {didSet {squareLayer.isHidden = isSelected}}override func layoutSubviews() {super.layoutSubviews()let width = bounds.widthlet height = bounds.height// 大圆bigCircleLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)// 小圆let smallWidth = 60.0smallCircleLayer.frame = CGRect(x: (width - smallWidth) / 2, y: (height - smallWidth) / 2, width: smallWidth, height: smallWidth)// 方形let squareWidth = 25.0squareLayer.frame = CGRect(x: (width - squareWidth) / 2, y: (height - squareWidth) / 2, width: squareWidth, height: squareWidth)}
}
  1. 大圆图层(bigCircleLayer):这个圆形图层充当按钮的背景,使用 CALayer 创建,设置了半透明白色背景,使其看起来既简洁又具有层次感。
  2. 小圆图层 (smallCircleLayer):这个圆形图层在大圆内部显示,颜色为纯白,模拟了录制按钮中的核心圆形。
  3. 方形图层(squareLayer):这个图层使用 CAGradientLayer 绘制了一个渐变色的矩形,位于小圆的中心。它的显示与按钮的选择状(isSelected)态相关,状态为selected时,方形会被隐藏。

通过这种设计,MWRecordingButton在录制和暂停状态之间切换时,能够清晰地反馈状态,用户一眼就能判断当前按钮的作用,同时通过动态的图层切换,使得界面更加生动。

MWRecordingNavigationView:导航栏

MWRecordingNavigationView 是自定义的视频录制界面顶部导航栏视图,它包含了三个主要组件:返回按钮、切换摄像头按钮和一个可定制的中间文案标签。这个视图旨在为用户提供流畅的操作体验,在录制过程中可以方便地进行控制和反馈。

以下是  MWRecordingNavigationView 类的实现代码:

import UIKitclass MWRecordingNavgationView: UIView {/// 返回按钮private let backButton = UIButton()/// 切换摄像头按钮private let switchCameraButton = UIButton()/// 返回按钮点击事件var backButtonClickBlock: (() -> Void)?/// 切换摄像头按钮点击事件var switchCameraButtonClickBlock: (() -> Void)?/// 隐藏显示切换按钮var isHiddenSwitchCameraButton: Bool = false {didSet {switchCameraButton.isHidden = isHiddenSwitchCameraButton}}override init(frame: CGRect) {super.init(frame: frame)setupView()setLayout()setEvent()}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setupView() {// 返回按钮addSubview(backButton)backButton.setImage(UIImage(named: "navigation_back_white"), for: .normal)// 切换摄像头按钮addSubview(switchCameraButton)switchCameraButton.setImage(UIImage(named: "navigation_switch_camera"), for: .normal)}private func setLayout() {// 设置返回按钮的布局backButton.snp.makeConstraints { make inmake.leading.equalToSuperview().offset(16.0)make.centerY.equalToSuperview()make.width.height.equalTo(32.0)}// 设置切换摄像头按钮的布局switchCameraButton.snp.makeConstraints { make inmake.trailing.equalToSuperview().offset(-16.0)make.centerY.equalToSuperview()make.width.height.equalTo(32.0)}}private func setEvent() {// 返回按钮点击事件backButton.addTarget(self, action: #selector(backButtonClick), for: .touchUpInside)// 切换摄像头按钮点击事件switchCameraButton.addTarget(self, action: #selector(switchCameraButtonClick), for: .touchUpInside)}@objc private func backButtonClick() {backButtonClickBlock?()}@objc private func switchCameraButtonClick() {switchCameraButtonClickBlock?()}
}
  1. 返回按钮(backButton):通过UIButton实现,提供一个简单的返回操作,用户可以随时退出当前的录制界面。图标为白色箭头,易于辨识。
  2. 切换摄像头(switchCameraButton):也是一个UIButton,用于切换前后摄像头。在某些应用场景下,用户可能需要切换摄像头,这个按钮就提供了这个功能。

结语

在本文中,我们详细探讨了 iOS 视频录制功能中的自定义 UI 实现,包括预览视图、控制视图和导航栏的设计与实现。这些自定义组件不仅提升了用户体验,还确保了操作的流畅性和可控性。通过自定义 MWRecordingPreview 视图,我们为录制过程提供了实时的视频预览;通过设计 MWRecordingControlView 和 MWRecordingButton,我们实现了清晰直观的录制控制;而 MWRecordingNavigationView 则为用户提供了便捷的导航和摄像头切换功能。

这些 UI 组件的灵活性和可定制性,使得在开发过程中可以根据需求对界面进行调整与扩展。在未来的版本中,您可以继续根据产品需求对这些视图进行优化和改进,带给用户更加丰富和优质的录制体验。

通过对这些自定义 UI 组件的解析,我们希望能够帮助开发者们更好地理解和实现 iOS 视频录制功能,并为其应用增添更多个性化的设计。感谢您的阅读,期待您的探索和创新!

相关文章:

深入解析iOS视频录制(二):自定义UI的实现

深入解析 iOS 视频录制(一):录制管理核心MWRecordingController 类的设计与实现 深入解析iOS视频录制(二):自定义UI的实现​​​​​​​ 深入解析 iOS 视频录制(三):完…...

基于开源Odoo、SKF Phoenix API与IMAX-8数采网关的圆织机设备智慧运维实施方案 ——以某纺织集团圆织机设备管理场景为例

一、方案背景与需求分析 1.1 纺织行业设备管理痛点 以某华东地区大型纺织集团为例,其圆织机设备管理面临以下挑战: 非计划停机损失高:圆织机主轴轴承故障频发,2024年单次停机损失达12万元(停机8小时导致订单延误&am…...

Deepseek 万能提问公式:高效获取精准答案

### **Deepseek 万能提问公式:高效获取精准答案** 在使用 Deepseek 或其他 AI 工具时,提问的质量直接决定了答案的精准度和实用性。以下是一个万能的提问公式回答: --- ### **1. 明确背景(Context)** - **作用**…...

SQL进阶技巧:如何统计用户跨端消费行为?

目录 0 问题描述 2 问题剖析 技术难点解析 3 完整解决方案 步骤1:构造全量日期平台组合 步骤2:用户行为标记 步骤3:最终关联聚合 4 核心技巧总结 5 复杂度评估 往期精彩 0 问题描述 支出表: Spending +-------------+---------+ | Column Name | Type | +-----…...

DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地

对于个人开发者或尝鲜者而言,本地想要部署 DeepSeek 有很多种方案,但是一旦涉及到企业级部署,则步骤将会繁琐很多。 比如我们的第一步就需要先根据实际业务场景评估出我们到底需要部署什么规格的模型,以及我们所要部署的模型&…...

算法——舞蹈链算法

一,基本概念 算法简介 舞蹈链算法(Dancing Links,简称 DLX)是一种高效解决精确覆盖问题的算法,实际上是一种数据结构,可以用来实现 X算法,以解决精确覆盖问题。由高德纳(Donald E.…...

【复现DeepSeek-R1之Open R1实战】系列5:SFT源码逐行深度解析

目录 3 SFT源码分析3.1 accelerate3.1.1 关键特性3.1.2 使用场景3.1.3 简单示例 3.2 代码主入口3.3 设置随机种子3.4 设置Log3.5 加载数据集3.6 加载Tokenizer3.7 模型参数配置初始化3.8 初始化SFT Trainer3.9 开始训练3.9.1 主函数3.9.2 核心循环3.9.3 单步训练3.9.4 原始Loss…...

WPF8-常用控件

目录 写在前面:1. 按钮控件1.1. Button 按钮1.2. RepeatButton:长按按钮1.3. RadioButton:单选按钮 2. 数据显示控件2.1. TextBlock:只读文本控件2.2. Lable:标签 显示文本控件2.3. ListBox:显示可选择项的列表2.4. DataGrid&…...

单元测试整理

在国外软件开发中,单元测试必不可少,但是国内并不太重视这一块,一个好的单元测试可以提前发现很多问题,也减去和测试battle的时间 Spring单元测试 JUnit4 RunWith 指明单元测试框架 e.g. RunWith(SpringJUnit4ClassRunner.cla…...

代码随想录刷题day24|(字符串篇)151.反转字符串中的单词

一、题目思路 1.快慢指针移除字符串首尾以及单词中的多余空格 类似前面数组篇--移除元素代码随想录刷题day02|(数组篇)27.移除元素、26.删除有序数组中的重复项_代码随想录网站-CSDN博客 快指针fast遍历整个字符串,慢指针slow指向新字符串…...

六、敏捷开发工具:项目管理工具

一、敏捷开发工具 在敏捷开发过程中,项目管理工具是支持团队高效协作、任务跟踪和项目进度控制的关键因素。随着敏捷方法的普及,市场上出现了多种工具来帮助团队进行需求管理、任务分配、进度跟踪以及反馈收集等任务。本文将对常用的敏捷开发项目管理工具(如Jira、Trello、…...

VMware按照的MacOS升级后无法联网

背景 3年前公司使用Flutter开发了一款app,现在app有微小改动需要重新发布到AppStore 问题 问题是原来的Vmware搭建的开发环境发布App失败了 提示:App需要使用xcode15IOS 17 SDK重新构建,这样的话MacOS至少需要升级到13.5 Xcode - 支持 - Ap…...

I2C、SPI、UART

I2C:串口通信,同步,半双工,双线(数据线SDA时钟线SCL),最大距离1米到几米 SPI(串行外设接口):串口通信,同步,全双工,四线&…...

3.2 Hugging Face Transformers库深度解析:大模型开发的一站式解决方案

Hugging Face Transformers库深度解析:大模型开发的一站式解决方案 一、Transformers库定位:NLP领域的"模型工厂" 1.1 核心定义与技术定位 Hugging Face Transformers 是一个开源的Python库,专为自然语言处理(NLP)、计算机视觉(CV)和语音任务设计。它提供:…...

DeepSeek V3和R1

DeepSeek V3 和 R1 是深度求索(DeepSeek)推出的两款大模型,基于混合专家架构(MoE),但在设计目标、训练方法和应用场景上存在显著差异。以下是两者的详细对比与补充内容: DeepSeek V3和R1 一、模…...

【操作系统】深入理解Linux物理内存

物理内存的组织结构 我们平时所称的内存也叫随机访问存储器也叫 RAM 。RAM 分为两类: 一类是静态 RAM( SRAM ),这类 SRAM 用于 CPU 高速缓存 L1Cache,L2Cache,L3Cache。其特点是访问速度快,访…...

6.【线性代数】—— 列空间和零空间

六 列空间和零空间 1. 列空间 C(A)2. 零空间 N(A)2.1 定义2.2 为什么零空间是一个子空间?2.3 Axb的解空间,是一个子空间吗? 1. 列空间 C(A) [ c o l 11 c o l 21 c o l 31 c o l 12 c o l 22 c o l 32 c o l 13 c o l 23 c o l 33 ] ⏟ A [ a…...

记一次一波三折的众测SRC经历

视频教程和更多福利在我主页简介或专栏里 (不懂都可以来问我 专栏找我哦) 目录: 前言 波折一:RCE漏洞利用失败 波折二:SQL时间盲注 波折三:寻找管理后台 总结 前言 先谈个人SRC心得体会吧,我虽…...

Java中的Thread.sleep(0)你了解多少

在Java中,Thread.sleep(long millis)方法用于使当前线程暂停执行指定的时间(以毫秒为单位)。它通常用于控制线程的执行节奏、避免过度占用CPU资源或实现任务的延迟。然而,Thread.sleep(0)作为Thread.sleep方法的一种特殊用法&…...

POI优化Excel录入

57000单词原始录入时间258S 核心代码: List<Word> wordBookList ExcelUtil.getReader(file.getInputStream()).readAll(Word.class);if (!CollectionUtil.isEmpty(wordBookList)) {for (Word word : wordBookList) {//逐条向数据库中插入单词wordMapper.insert(word);}…...

HarmonyOS进程通信及原理

大家好&#xff0c;我是学徒小z&#xff0c;最近在研究鸿蒙中一些偏底层原理的内容&#xff0c;今天分析进程通信给大家&#xff0c;请用餐&#x1f60a; 文章目录 进程间通信1. 通过公共事件&#xff08;ohos.commonEventManager&#xff09;公共事件的底层原理 2. IPC Kit能…...

DeepSeek核心算法解析:如何打造比肩ChatGPT的国产大模型

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》&#xff08;人工智能科学与技术丛书&#xff09;【陈敬雷编著】【清华大学出版社】 文章目录 DeepSeek大模型技术系列一DeepSeek核心算法解析&#xff1a;如何…...

【算法】双指针(上)

目录 双指针 左右指针(对撞指针) 快慢指针 移动零 双指针解题 复写零 暴力解题 双指针解题(快慢指针) 快乐数 双指针解题(快慢指针) 盛最多水的容器 暴力解题(会超时) 双指针解题(左右指针) 有效三角形的个数 暴力解题 双指针解题(左右指针) 双指针 常见的双指…...

深度学习模型常用激活函数集合

激活函数是深度学习模型中的关键组成部分&#xff0c;用于引入非线性特性&#xff0c;使神经网络能够学习复杂的模式和映射关系&#xff1b;神经网络本质上是一个复合函数。如果没有激活函数&#xff0c;无论网络有多少层&#xff0c;其输出都只是输入的线性组合。激活函数通过…...

WebAssembly 3.0发布:浏览器端高性能计算迎来新突破!

“WebAssembly 3.0来了&#xff0c;浏览器端的高性能计算将彻底改变&#xff01;”2025年&#xff0c;WebAssembly&#xff08;Wasm&#xff09;迎来了重大更新——WebAssembly 3.0正式发布。这次更新不仅支持多线程和SIMD指令集&#xff0c;还优化了内存管理&#xff0c;让浏览…...

ERP对制造业务有何价值?

ERP 的定义 在定义 ERP 之前&#xff0c;我们先从其首字母缩写说起&#xff0c;ERP 代表企业资源规划。我们可以将 ERP 定义为一种企业软件&#xff0c;它帮助组织管理日常业务。从根本上讲&#xff0c;ERP 将客户管理、人力资源、商业智能、财务管理、库存以及供应链功能整合…...

MySQL5.7 创建用户并授予超管权限脚本

记录MySQL5.7 创建新用户并授予超管权限脚本 用户与密码可任意设置 创建用户并设置密码 CREATE USER zhangsan % identified by 123456oo;修改用户密码 UPDATE USER set authentication_stringpassword("Abc123!") where user"zhangsan ";授予用户超管权…...

芝加哥学派(Chicago School):金融与经济学的创新力量(中英双语)

芝加哥学派&#xff1a;金融与经济学的创新力量 在经济学和金融学的历史上&#xff0c;有一个学派的影响力不容忽视&#xff0c;那就是芝加哥学派&#xff08;Chicago School&#xff09;。芝加哥学派不仅在学术界广受推崇&#xff0c;也深刻影响了全球的经济政策和金融市场。…...

Pytorch实现论文之一种基于扰动卷积层和梯度归一化的生成对抗网络

简介 简介:提出了一种针对鉴别器的梯度惩罚方法和在鉴别器中采用扰动卷积,拟解决锐梯度空间引起的训练不稳定性问题和判别器的记忆问题。 论文题目:A Perturbed Convolutional Layer and Gradient Normalization based Generative Adversarial Network(一种基于扰动卷积层…...

哈希表(C语言版)

文章目录 哈希表原理实现(无自动扩容功能)代码运行结果 分析应用 哈希表 如何统计一段文本中&#xff0c;小写字母出现的次数? 显然&#xff0c;我们可以用数组 int table[26] 来存储每个小写字母出现的次数&#xff0c;而且这样处理&#xff0c;效率奇高。假如我们想知道字…...