【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文件中直接使用


总结

计算器的仿写其实不难,最难的部分是对表达式的处理,有许多细节需要注意

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

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

相关文章

【Java基础面试十二】、说一说你对面向对象的理解

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a; 说一说你对面向对象的理…

C++前缀和算法:构造乘积矩阵

基础知识点 C算法&#xff1a;前缀和基础 题目 给你一个下标从 0 开始、大小为 n * m 的二维整数矩阵 grid &#xff0c;定义一个下标从 0 开始、大小为 n * m 的的二维矩阵 p。如果满足以下条件&#xff0c;则称 p 为 grid 的 乘积矩阵 &#xff1a; 对于每个元素 p[i][j] …

【LeetCode热题100】--75.颜色分类

75.颜色分类 方法一&#xff1a;使用单指针 class Solution {public void sortColors(int[] nums) {int n nums.length;int ptr 0;for(int i 0;i<n;i){if(nums[i] 0){int tmp nums[i];nums[i] nums[ptr];nums[ptr] tmp;ptr;}}for(int i ptr;i<n;i){if(nums[i] …

【Java基础面试十三】、面向对象的三大特征是什么?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;面向对象的三大特征是什…

MySQL单表查询基础综合练习

一、单表查询 素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 v…

Linux文件管理(上)

一、VIM编辑器 1、vi概述 vi&#xff08;visual editor&#xff09;编辑器通常被简称为vi&#xff0c;它是Linux和Unix系统上最基本的文本编辑器&#xff0c;类似于Windows 系统下的notepad&#xff08;记事本&#xff09;编辑器。 2、vim编辑器 Vim(Vi improved)是vi编辑器…

联邦学习+梯度+梯度剪枝

联邦学习需要参与者在每一次的本地训练后&#xff0c;上传所更新的模型参数并与其他参与者共享&#xff0c;而参数更新中仍有可能包含所有者的敏感信息 解决方案&#xff1a; 加密方法&#xff08;安全多方计算、同态加密&#xff09;通过将明文编码为密文的方式&#xff0c;…

基于模型预测人工势场的船舶运动规划方法,考虑复杂遭遇场景下的COLREG(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

1数据结构的分类,算法效率的度量

一&#xff0c;数据结构的定义和分类 数据结构&#xff1a;数据之间的关系即数据的逻辑结构&#xff0c;因为要存储到计算机里&#xff0c;所以视为将这个数据的逻辑结构映射到存储器里。即数据因为自身的和其他的数据的关系而在计算机内存储的方式。我们就归类了一些类型。 二…

21-数据结构-内部排序-交换排序

简介&#xff1a;主要根据两个数据进行比较从而交换彼此位置&#xff0c;以此类推&#xff0c;交换完全部。主要有冒泡和快速排序两种。 目录 一、冒泡排序 1.1简介&#xff1a; 1.2代码&#xff1a; 二、快速排序 1.1简介&#xff1a; 1.2代码&#xff1a; 一、冒泡排序…

YOLO目标检测——安全帽手套数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;主要应用于监控视频中工作人员是否佩戴安全帽或手套的场景。数据集说明&#xff1a;YOLO目标检测数据集&#xff0c;类别有&#xff1a;手套、头盔、非头盔、人、鞋、背心、赤膊&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富。使用la…

The given SOAPAction http__xxxxx_xx does not match an operation

这是在客户端调用服务端接口时报出的错误&#xff0c;主要是客户端在调用时设置了SOAPAction&#xff0c;参考如下&#xff1a; 解决方案 在注解WebMethod() 中加上action注解&#xff0c;设置上一模一样的SOAPAction即可&#xff0c;如下&#xff1a; WebMethod(action &qu…

小程序设计基本微信小程序的旅游社系统

项目介绍 现今市面上有关于旅游信息管理的微信小程序还是比较少的&#xff0c;所以本课题想对如今这么多的旅游景区做一个收集和分类。这样可以给身边喜欢旅游的朋友更好地推荐分享适合去旅行的地方。 前端采用HTML架构&#xff0c;遵循HTMLss JavaScript的开发方式&#xff0…

【CANoe】TX Self-ACK自应答配置与CPAL实现

一、引言 在测试CAN&CANFD通信或者网络管理的时候&#xff0c;我们经常遇到使用报文&#xff08;网络管理报文或者通信报文&#xff09;唤醒被测件这个测试点&#xff0c;如果测试比较多的情况下&#xff0c;我们就会发现&#xff0c;如果CANoe没有接被测件或者被测件没有…

CSS 效果:多列文字,第一行对齐,flex方式元素被挤压

如图效果&#xff1a;2列&#xff0c;第一列只有一行&#xff0c;第二列多行。要求第一行对齐 实现&#xff1a;使用flex 如果不配置flex-shrink的话&#xff0c;第一列会被挤压 给第一列&#xff1a;备注配置压缩属性&#xff1a; flex-shrink&#xff1a;0。 <!DOCTYPE…

发现了一个牛逼的网站 可以免费使用chatGPT(看到最后)

最近,打工人们集体陷入了一场焦虑。“一觉醒来,我感觉自己快要失业了……”“身为文字工作者,我该如何自保饭碗?”“人工智能到底会不会完全取代人类的工作?” ChatGPT最近都听说了吧?据说,改论文、敲代码、写文案……只有你想不到的,没有人家办不成的! 它是什么? …

谜题(Puzzle, ACM/ICPC World Finals 1993, UVa227)rust解法

有一个5*5的网格&#xff0c;其中恰好有一个格子是空的&#xff0c;其他格子各有一个字母。一共有4种指令&#xff1a;A, B, L, R&#xff0c;分别表示把空格上、下、左、右的相邻字母移到空格中。输入初始网格和指令序列&#xff08;以数字0结束&#xff09;&#xff0c;输出指…

java 两个list比较,删除相同的元素

概述 在Java开发中&#xff0c;经常需要比较两个List并删除相同的元素。本文将介绍整个流程&#xff0c;并提供相应的代码示例&#xff0c;帮助新手开发者完成这个任务。 流程 下面是比较两个List并删除相同元素的流程&#xff1a; 代码示例 创建两个List 我们首先需要创建两…

从旅游发展大会,看长沙的“落子”与“棋道”

文&#xff5c;新熔财经 作者&#xff5c;石榴 中秋国庆假期作为今年的最后一个小长假&#xff0c;全国各地果断祭出自己的“杀手锏”&#xff0c;不过&#xff0c;虽是百花齐放&#xff0c;但星城长沙仍然是最亮眼的存在之一。 全省文化旅游统计监测系统显示&#xff0c;中…

6-k8s-控制器版本管理

文章目录 一、概念介绍二、配置介绍三、版本生成测试四、版本回滚测试 一、概念介绍 什么是控制器&#xff1a;在k8s中&#xff0c;控制器是一种用于控制和管理Pod的管理器&#xff0c;包括Deployment、ReplicaSet、StatefulSet等。 什么是控制器版本管理&#xff1a;是指对于…