【iOS】计算器仿写
文章目录
- 前言
- 一、构建View界面
- 二、Model中进行数据处理
- 三、Controller层实现View与Model交互
- 总结
前言
在前两周组内进行了计算器的仿写,计算器仿写主要用到了MVC框架的思想以及数据结构中用栈进行四则运算的思想,还有就是对OC中的字符串进行各种判错操作处理。
接下来笔者将简单介绍一下利用OC实现计算机的基本思路
一、构建View界面
我们先来看一下计算机界面实现的具体效果:
在实现View界面时,笔者使用了Masonry进行布局,因为计算器界面按钮的排序是有规律的,因此使用Masonry能让我们的布局更加轻松。
下面给出创建部分按钮的示例:
for (int i = 0; i < 4; i++) {//先循环创建16个按钮for (int j = 0; j < 4; j++) {_baseButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];_baseButton.layer.cornerRadius = SIZE / 2;//圆形按钮_baseButton.titleLabel.font = [UIFont systemFontOfSize:42];_baseButton.tag = j + 4 + i * 4;[self addSubview:_baseButton];[_baseButton mas_makeConstraints:^(MASConstraintMaker *make) {//从底部开始约束make.bottom.equalTo(self).offset(-(75 + (SIZE + 17) * (i + 1)));make.left.equalTo(self).offset(5 + [UIScreen mainScreen].bounds.size.width / 4 * j);make.width.equalTo(@SIZE);make.height.equalTo(@SIZE);}];if (j < 3) {//竖列if (i < 3) {//横行[_baseButton setBackgroundColor:[UIColor colorWithWhite:0.15 alpha:1]];[_baseButton setTitle:[NSString stringWithFormat:@"%d", j + 1 + i * 3] forState:UIControlStateNormal];[_baseButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];} else {[_baseButton setBackgroundColor:[UIColor lightGrayColor]];[_baseButton setTitle:grayArray[j] forState:UIControlStateNormal];[_baseButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];}} else {//橘色符号[_baseButton setBackgroundColor:[UIColor colorWithRed:0.9 green:0.58 blue:0 alpha:1]];[_baseButton setTitle:orangeArray[i] forState:UIControlStateNormal];[_baseButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];}if (j == 0 && i == 3) {_baseButton.titleLabel.font = [UIFont systemFontOfSize:34];}}}
二、Model中进行数据处理
根据MVC框架的思想,我们的Model层是负责提供数据接口给controller使用,因此我们需要将处理好的数据返回给controller层。我们在此对其进行四则运算的逻辑操作。
这里简单介绍一下我们的四则运算,本质上是使用运算符号优先级来判断是否入栈出栈,笔者后面会单独写博客讲述。这里有人会先将中缀表达式转为后缀表达式再去计算结果,笔者这里直接使用中缀表达式计算结果
代码:
- (instancetype)init {self = [super init];if (self) {self.stackArray = [NSMutableArray arrayWithCapacity:Maxsize];self.stackSize = Maxsize;}return self;
}char Precede(char theta1, char theta2) {int i, j;char pre[7][7] = {{'>', '>', '<', '<', '<', '>', '>'},{'>', '>', '<', '<', '<', '>', '>'},{'>', '>', '>', '>', '<', '>', '>'},{'>', '>', '>', '>', '<', '>', '>'},{'<', '<', '<', '<', '<', '=', '0'},{'>', '>', '>', '>', '0', '>', '>'},{'<', '<', '<', '<', '<', '0', '='}};switch (theta1) {case '+': i = 0; break;case '-': i = 1; break;case '*': i = 2; break;case '/': i = 3; break;case '(': i = 4; break;case ')': i = 5; break;case '=': i = 6; break;}switch (theta2) {case '+': j = 0; break;case '-': j = 1; break;case '*': j = 2; break;case '/': j = 3; break;case '(': j = 4; break;case ')': j = 5; break;case '=': j = 6; break;}return pre[i][j];
}double Operate(double a, char theta, double b) {switch (theta) {case '+': return a + b;case '-': return a - b;case '*': return a * b;case '/':if (b != 0) {return a / b;} else {NSLog(@"Divisor can not be zero!");exit(0);}}return 0;
}int In(char c) {switch (c) {case '+':case '-':case '*':case '/':case '(':case ')':case '=':return 1;default:return 0;}
}- (NSString *) evaluateExpression:(NSString *)exp {_OPND = [[Model alloc] init];//数字栈_OPTR = [[Model alloc] init];//符号栈double a, b, theta, X1, X2;char ch;NSInteger i = 0;NSInteger fuhaoFlag = 0;NSInteger kuohaoFlag = 0;NSInteger fuhaoBegin = 0;[_OPTR push:'='];ch = [exp characterAtIndex:i++];if (ch == '-') {ch = [exp characterAtIndex:i++];fuhaoFlag = 1;}while (ch != '=' || [_OPTR getTop] != '=') {if (In(ch)) {if (ch == '(') {kuohaoFlag = 1;}if (ch == '-' && [exp characterAtIndex:i - 2] == '(') {fuhaoFlag = 1;kuohaoFlag = 0;ch = [exp characterAtIndex:i++];continue;}switch (Precede([_OPTR getTop], ch)) {case '<':[_OPTR push:ch];ch = [exp characterAtIndex:i++];break;case '>':[_OPTR pop:&theta];[_OPND pop:&b];[_OPND pop:&a];if (theta == '/' && b == 0) {return @"error";}[_OPND push:Operate(a,theta,b)];break;case '=':[_OPTR pop:&theta];ch = [exp characterAtIndex:i++];break;}} else if (isdigit(ch)) {X1 = ch - '0';[_OPND push:X1];X2 = X1;ch = [exp characterAtIndex:i++];while (isdigit(ch)) {X1 = ch - '0';X2 = 10 * X2 + X1;ch = [exp characterAtIndex:i++];}if (ch == '.') {ch = [exp characterAtIndex:i++];double decimal = 0.0;double j = 1;while (isdigit(ch)) {double f = (double)(ch - '0');decimal = f / (pow(10, j));j++;ch = [exp characterAtIndex:i++];X2 += decimal;}}if (fuhaoFlag == 0 && fuhaoBegin == 0) {double tmpX1;[_OPND pop:&tmpX1];[_OPND push:X2];} else {double tmpX1;[_OPND pop:&tmpX1];[_OPND push:-X2];fuhaoFlag = 0;fuhaoFlag = 0;}} else {return @"error";}}double result = [_OPND getTop];NSString *resultString = [NSString stringWithFormat:@"%f", result];resultString = [self removeFloatAllZeroByString:resultString];return resultString;
}
在OC中我们初始化两个栈,一个存储数字,一个存储符号,然后不断将符号与数字入栈出栈,直至碰到“=”。
一些判错操作:
我们也需要对我们的表达式进行一些判错处理,例如运算符相连或事括号数量的不匹配等问题,演示结果如下:
或是小数点不匹配与结果末尾有多余0的情况:
这些判错操作的部分是计算器最复杂的部分,需要多多琢磨。
三、Controller层实现View与Model交互
在MVC中我们的Controller的作用是实现View与Model交互,因此我们需要在Controller层中实现我们界面按钮的点击事件并将其转换为字符串,同时将生成的字符串传入Model层进行数据处理,如果没有判错则将其结果输出。
- (void)viewDidLoad {[super viewDidLoad];_calculatorView= [[View alloc] init];_calculatorView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);[self.view addSubview:_calculatorView];//为视图中的按钮在controller中添加事件for (UIView *subview in self.calculatorView.subviews) {if ([subview isKindOfClass:[UIButton class]]) {UIButton *button = (UIButton *)subview;[button addTarget:self action:@selector(pressButton:) forControlEvents:UIControlEventTouchUpInside];}}_calculatorModel= [[Model alloc] init];}
这里需要注意,因为笔者理解的MVC中View只负责界面的绘制,并不用处理界面的逻辑,例如界面中控件的点击事件,因此这里需要再controller中使用如下代码对其进行点击事件的添加:
for (UIView *subview in self.calculatorView.subviews) {if ([subview isKindOfClass:[UIButton class]]) {UIButton *button = (UIButton *)subview;[button addTarget:self action:@selector(pressButton:) forControlEvents:UIControlEventTouchUpInside];}}
接下来给出一些对按钮中的点击事件的代码:
//左右括号if (btn.tag == 17) {if (![_calculatorView.printfLabel.text isEqual: @"0"]) {_calculatorView.printfLabel.text = [_calculatorView.printfLabel.text stringByAppendingString:@"("];} else {_calculatorView.printfLabel.text = @"(";} }if (btn.tag == 18) {if (![_calculatorView.printfLabel.text isEqual: @"0"]) {_calculatorView.printfLabel.text = [_calculatorView.printfLabel.text stringByAppendingString:@")"];} else {_calculatorView.printfLabel.text = @")";} }if (btn.tag == 3) {if ([_calculatorModel error:_calculatorView.printfLabel.text] == 1 ) {_calculatorView.printfLabel.text = @"error";} else {_calculatorView.printfLabel.text = [_calculatorView.printfLabel.text stringByAppendingString:@"="];NSString *result = [_calculatorModel evaluateExpression:_calculatorView.printfLabel.text];NSLog(@"%@", result);_calculatorView.printfLabel.text = result;}}
这里需要注意我们在VIew中创建按钮时已经对其tag进行赋值,因此可在controller文件中直接使用
总结
计算器的仿写其实不难,最难的部分是对表达式的处理,有许多细节需要注意
相关文章:

【iOS】计算器仿写
文章目录 前言一、构建View界面二、Model中进行数据处理三、Controller层实现View与Model交互总结 前言 在前两周组内进行了计算器的仿写,计算器仿写主要用到了MVC框架的思想以及数据结构中用栈进行四则运算的思想,还有就是对OC中的字符串进行各种判错操…...

华为认证 | 华为HCIE认证该怎样备考?
华为HCIE认证是华为认证的最高级别,拥有了华为HCIE认证就代表拥有了华为官方认可的专家级技术水平。 因此HCIE认证的考试难度是非常高的,备考华为认证HCIE需要一定的准备和规划。 整理了一些简单易懂的指南,希望对各位备考的小伙伴一些帮助…...

10月份stable diffusion animatediff等插件使用指南,又来更新了
插件一直会更新,包含了基本市面上流行的90%插件,好用的插件更是不会错过,往期插件请看往期文章,如果你没有时间一直关注sd更新的进展,请关注我,一个月用几个小时看一下我的文章,最短时间跟进sd。…...

抓包工具charles修改请求和返回数据
数据篡改的主要使用场景: (1)mock场景,mock入参和返回值参数,实现mock测试 (2)安全测试,对于支付金额等比较重要的字段,可以修改请求参数来进行安全测试 1.首先选择要…...

matlab中绘制 维诺图(Voronoi Diagram)
1.专业术语(相关概念): 基点Site:具有一些几何意义的点 细胞Cell:这个Cell中的任何一个点到Cell中基点中的距离都是最近的,离其他Site比离内部Site的距离都要远。 Cell的划分:基点Site与其它的…...

Mybatis TypeHandler 介绍及使用
Mybatis TypeHandler类型转换器是负责Java类和jdbc类型之间的转换 主要涉及到下面这几个类: TypeHandler 类型转换器的顶层接口BaseTypeHandler 抽象类继承自TypeHandler,Mybatis中所有的类型转换器实现均继承他。TypeHandlerRegistry 类型转换器注册器…...

Linux SVN 命令详解
1、将文件 checkout 到本地目录 svn checkout path(path是服务器上的目录) 例如:svn checkout svn://192.168.1.1/pro/domain 简写:svn co 2、往版本库中添加新的文件 svn add file 例如:svn add test.php(添加test.…...

Maven依赖引入的优先机制
xxxx待持续更新...

全开源无加密跨境电商购物网站系统源码(无货源模式+多语言+多货币)
在全球化的时代背景下,跨境电商成为了越来越受欢迎的消费方式,而建立一个源码无加密多语言跨境购物网站系统是一个具有挑战性的任务,但完全可行。以下是这个过程的一些主要步骤: 1. 确定需求和功能规划:先确定网站需要…...

Python常用视频编辑操作——读取与保存视频、更改帧数、拼接视频、视频语音合并、视频与图像互转等
1.更改视频帧数 降低视频帧数,简单的操作只能降低视频帧数,如果要增加视频帧数,那就要使用深度学习进行插帧处理: import cv2 from moviepy.editor import * def change_fps(inpt_path,output_path,fps):# 加载视频video Video…...

从javascript到vue再到react的演变
当提到前端开发中的框架时,JavaScript、Vue.js和React.js是三个最常见的名词。它们代表了Web开发中不同的技术选择和演变过程。本文将探讨JavaScript从原生到Vue.js再到React.js的演变,以及每个阶段的特点和优势。 JavaScript: 动态语言的基础 JavaScr…...

50个渗透(黑客)常用名词及解释
目录 前言一、渗透测试1. 渗透测试:2. 黑盒测试:3. 白盒测试:4. 社会工程学:5. 缓冲区溢出:6. 拒绝服务攻击:7. DDoS攻击:8. XSS攻击:9. CSRF攻击:10. SQL注入࿱…...

开源游戏引擎和模拟器的项目合集 | 开源专题 No.38
yuzu-emu/yuzu Stars: 26.2k License: GPL-3.0 yuzu是一款全球最受欢迎的开源Nintendo Switch模拟器,由Citra创建者编写。它采用C语言编写,并具有可移植性,在Windows和Linux上进行积极维护。该模拟器能够全速运行大多数商业游戏,…...

ELK + Filebeat 分布式日志管理平台部署
ELK Filebeat 分布式日志管理平台部署 1、前言1.1日志分析的作用1.2需要收集的日志1.3完整日志系统的基本特征 2、ELK概述2.1ELK简介2.2为什么要用ELK?2.3ELK的组件 3、ELK组件详解3.1Logstash3.1.1简介3.1.2Logstash命令常用选项3.1.3Logstash 的输入和输出流3.1.4Logstash配…...

Stable Diffusion原理
一、Diffusion扩散理论 1.1、 Diffusion Model(扩散模型) Diffusion扩散模型分为两个阶段:前向过程 反向过程 前向过程:不断往输入图片中添加高斯噪声来破坏图像反向过程:使用一系列马尔可夫链逐步将噪声还原为原始…...

2022年亚太杯APMCM数学建模大赛A题结晶器熔剂熔融结晶过程序列图像特征提取及建模分析求解全过程文档及程序
2022年亚太杯APMCM数学建模大赛 A题 结晶器熔剂熔融结晶过程序列图像特征提取及建模分析 原题再现: 连铸过程中的保护渣使钢水弯液面隔热,防止钢水在连铸过程中再次氧化,控制传热,为铸坯提供润滑,并吸收非金属夹杂物…...

金融网站如何做好安全防护措施?
联网的发展为当代很多行业的发展提供了一个更为广阔的平台,而对于中国的金融业来说,互联网金融这一新兴理念已经为 人们所接受,且发展迅速。我们也都知道金融行业对互联网技术是非常严格的,这对互联网的稳定性和可靠性提出了较高的…...

2023年中国恋爱社区未来发展趋势分析:多元化盈利模式实现可持续发展[图]
恋爱社区指满足情侣之间互动、记录及娱乐需求,以维护情侣恋爱关系的虚拟社区。恋爱社区行业主要以线上APP的虚拟形式为用户提供相关服务,其业务包括情侣记录、情侣互动、情侣娱乐、公共社区、线上购物、增值服务。 恋爱社区主要业务 资料来源࿱…...

Elasticsearch:生成式人工智能带来的社会转变
作者:JEFF VESTAL 了解 Elastic 如何走在大型语言模型革命的最前沿 – 通过提供实时信息并将 LLM 集成到数据分析的搜索、可观察性和安全系统中,帮助用户将 LLM 提升到新的高度。 iPhone 社会转变:新时代的黎明 曾几何时,不久前…...

服务器数据恢复-RAID5中磁盘被踢导致阵列崩溃的服务器数据恢复案例
服务器数据恢复环境: 一台3U的某品牌机架式服务器,Windows server操作系统,100块SAS硬盘组建RAID5阵列。 服务器故障: 服务器有一块硬盘盘的指示灯亮黄灯,这块盘被raid卡踢出后,raid阵列崩溃。 服务器数据…...

负荷不均衡问题分析处理流程
一、负荷不均衡分析 负荷不均衡判断标准:4G同覆盖扇区内存在无线利用率大于50%的小区,且两两小区间无线利用率差值大于30%,判定为4G负荷不均衡扇区;5G同覆盖扇区内存在无线利用率大于50%的小区,且两两小区间无线利用率…...

Spring篇---第四篇
系列文章目录 文章目录 系列文章目录一、说说你对Spring的IOC是怎么理解的?二、解释一下spring bean的生命周期三、解释Spring支持的几种bean的作用域?一、说说你对Spring的IOC是怎么理解的? (1)IOC就是控制反转,是指创建对象的控制权的转移。以前创建对象的主动权和时机…...

算法通过村第十五关-超大规模|白银笔记|经典问题
文章目录 前言从40个亿中产生一个不存在的整数位图存储数据的原理使用10MB来存储如何确定分块的区间 用2GB内存在20亿的整数中找到出现次数最多的数从100亿个URL中查找的问题40亿个非负整数中找出两次的数。总结 前言 提示:人生之中总有空白,但有时&…...

Mini小主机All-in-one搭建教程6-安装苹果MacOS系统
笔者使用的ESXI7.0 Update 3 抱着试试的态度想安装一下苹果的MacOS系统 主要步骤有2个 1.解锁unlocker虚拟机系统 2.安装苹果MacOS系统 需要下载的文件 unlocker 这一步是最耗时间的,要找到匹配自己系统的unlocker文件。 https://github.com/THDCOM/ESXiUnloc…...

Android中使用Glide加载圆形图像或给图片设置指定圆角
一、Glide加载圆形头像 效果 R.mipmap.head_icon是默认圆形头像 ImageView mImage findViewById(R.id.image);RequestOptions options new RequestOptions().placeholder(R.mipmap.head_icon).circleCropTransform(); Glide.with(this).load("图像Uri").apply(o…...

Nginx 代理
目录 正向代理 反向代理 负载均衡 负载均衡的工作原理 优势和好处 算法和策略 应用领域 Nginx 的反向代理 应用场景 在网络通信中,代理服务器扮演着重要的角色,其中正向代理和反向代理是两种常见的代理服务器模式。它们在网络安全、性能优化和…...

uniapp(uncloud) 使用生态开发接口详情4(wangeditor 富文本, 云对象, postman 网络请求)
wangeditor 官网: https://www.wangeditor.com/v4/pages/01-%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8/01-%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8.html 这里用vue2版本,用wangeditor 4 终端命令: npm i wangeditor --save 开始使用 在项目pages > sy_news > add.vue 页面中…...

Halcon 中查看算子和函数的执行时间
1、在Halcol主窗口的底栏中的第一个图标显示算子或函数的执行时间,如下图: 2、在Halcon的菜单栏中选择【窗口】,在下拉框中选择【打开输出控制台】,进行查看算子或函数的执行时间,如下图:...

Python中的With ...as... 作用
Python中的with … as …作用: 1、通过with语句可以得到一个上下文管理器 2、执行对象 3、加载__enter__方法 4、加载__exit__方法 5、执行__enter__方法 6、as 可以得到enter的返回值 7、拿到对象执行相关操作 8、执行完了之后调用__exit__方法 9、如果遇到异常&a…...

腾讯云国际站服务器如何打开音频设备?
在使用腾讯云服务器进行音频处理或直播等活动时,或许需求翻开服务器的音频设备。本文将详细介绍如安在腾讯云服务器上翻开音频设备。 在腾讯云服务器上翻开音频设备的过程如下: 登录腾讯云服务器办理控制台 1.首先,需求登录腾讯云服务器的办理…...