【iOS】——仿写计算器

文章目录

  • 一、实现思路
  • 二、实现方法
  • 三、判错处理


一、实现思路

先搭建好MVC框架,接着在各个模块中实现各自的任务。首先要创建好UI界面,接着根据UI界面的元素来与数据进行互动,其中创建UI界面需要用到Masonry布局。
请添加图片描述

二、实现方法

在calculationView文件中只涉及到UI界面。
首先创建两个UITextField对象,一个用来显示输入到表达式,一个用来输出运算结果,接着创建一个数组用来存放button的名称,接着循环创建button对象即可。

创建button时需要设置button的tag属性,因为后面需要通过button的tag属性来进行逻辑判断。

self.textField01 = [[UITextField alloc] init];
self.textField01.backgroundColor = [UIColor blackColor];
self.textField02 = [[UITextField alloc] init];
self.textField02.backgroundColor = [UIColor blackColor];
self.buttonArray = [NSMutableArray arrayWithObjects:@"AC", @"(", @")", @"/", @"1", @"2", @"3", @"+", @"4", @"5", @"6", @"-", @"7", @"8", @"9", @"*",  @"0", @".", @"=", nil];for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {self.calculatorButton = [UIButton buttonWithType:UIButtonTypeCustom];NSString* buttonString = self.buttonArray[i * 4 + j];[self.calculatorButton setTitle:buttonString forState:UIControlStateNormal];self.calculatorButton.titleLabel.font = [UIFont systemFontOfSize:43];self.calculatorButton.titleLabel.textColor = [UIColor whiteColor];self.calculatorButton.backgroundColor = [UIColor grayColor];[self.calculatorButton addTarget:self action:@selector(pressButton:) forControlEvents:UIControlEventTouchUpInside];self.calculatorButton.layer.borderWidth = 2.0;self.calculatorButton.layer.cornerRadius = ButtonSize / 2;self.calculatorButton.layer.masksToBounds = YES;self.calculatorButton.tag = 100 + j + i*4;if (i == 0 && j < 3) {self.calculatorButton.backgroundColor = [UIColor colorWithWhite:0.6 alpha:0.9];self.calculatorButton.titleLabel.textColor = [UIColor blackColor];}if (j == 3) {self.calculatorButton.backgroundColor = [UIColor orangeColor];}[self addSubview:self.calculatorButton];[self.calculatorButton mas_makeConstraints:^(MASConstraintMaker *make) {make.top.equalTo(self).offset(90 + HEIGHT / 6 + HEIGHT / 8 + (ButtonSize + SideSize) * i);make.left.equalTo(self).offset(SideSize + (ButtonSize + SideSize) * j);make.width.equalTo(@ButtonSize);make.height.equalTo(@ButtonSize);}];}}

还需要在当前文件触发button的事件函数,因为要通过button的事件函数将当前button传值到CalculationViewController文件中。

我使用的协议传值进行

定义协议及协议方法

@protocol ButttonDelegate <NSObject>- (void)returnButton:(UIButton*)button;@end

定义代理对象

@property (nonatomic, weak)id<ButttonDelegate>delegate;

button事件函数触发代理方法

- (void)pressButton:(UIButton*)button {[self.delegate returnButton:button];
}

在CalculationViewController中定义协议方法

- (void)returnButton:(UIButton*)button;

在CalculationViewController中设置代理对象

 self.calculationView.delegate = self;

在CalculationViewController中实现协议方法

- (void)returnButton:(UIButton*)button {
- NSString* buttonStr = button.titleLabel.text;NSInteger buttonTag = button.tag;if (buttonTag == 100) {self.calculationView.textField01.text = @"";self.calculationView.textField02.text = @"";self.yunsuanStr = [[NSMutableString alloc] init];self.jieguoStr = [[NSString alloc] init];} else if (buttonTag == 118) {//四则运算}//
}

对于四则运算,我使用中缀表达式转后缀表达式,再利用后缀表达式进行计算。中缀转后缀定义一个符号栈,一个结果栈。

		char resultStack[100];int resultTop = -1;char operationStack[100];int operationTop = -1;NSString* ocStr =  self.yunsuanStr;const char* strs = [ocStr UTF8String];char str[1000] ;strcpy(str, strs) ;int length = (int)strlen(str);

后缀进行四则运算时定义一个新栈。

			double Stack[100];int StackTop = -1;char* token = strtok(resultStack, " ");while (token != NULL) {if (strcmp(token, "+") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b + a;Stack[++StackTop] = c;}else if (strcmp(token, "-") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b - a;Stack[++StackTop] = c;}else if (strcmp(token, "*") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b * a;Stack[++StackTop] = c;}else if (strcmp(token, "/") == 0) {double a = Stack[StackTop--];double b = Stack[StackTop--];double c = b / a;Stack[++StackTop] = c;}else if (strcmp(token, "!") == 0) {double c = Stack[StackTop--];c = -c;Stack[++StackTop] = c;}else {double num = atof(token);Stack[++StackTop] = num;}token = strtok(NULL, " ");}double result = Stack[StackTop--];

这里使用了atof()函数可以将字符串中的数字识别为double类型的浮点数。使用strtok()函数将结果栈的元素通过空格分割方便进行识别和运算。

对于负数的运算,我是将与“(”相邻的“-”转换为“!”,并用“!”进行负数转变,其中需要将“!“的优先级设置为最高

int Compare(char str) {if (str == '(' || str == ')') {return 0;}else if (str == '+' || str == '-') {return 1;}else if (str == '*' || str == '/') {return 2;} else if (str == '!') {return 3;} else {return -1;}
}

接着在输入字符串时进行识别

for (int i = 0; i < length; ++i) {if (str[i] == '(' && str[i + 1] == '-') {str[i + 1] = '!';}}

三、判错处理

对于括号匹配问题,我使用栈来处理,当读到“(”则入栈,读到“)”则栈顶元素出栈,最后判断栈是否为空即可。

- (int)kuoHaoMatch:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);char stack[100];int stackTop = -1;for (int i = 0; i < length; i++) {if (cstr[i] == '(') {stack[++stackTop] = cstr[i];}if (cstr[i] == ')') {stack[stackTop--];}}if (stackTop == -1) {return 1;}return 0;
}

对于符号匹配问题,两个运算符不能相邻,第一个位置不能为运算符(-除外),最后一个位置不能为运算符

- (int)fuHaoMatch:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);if (cstr[0] == '*' || cstr[0] == '/' || cstr[0] == '+') {return 0;}for (int i = 0; i < length; i++) {if ((cstr[i] == '*' && cstr[i+1] == '/') || (cstr[i] == '/' && cstr[i+1] == '*')) {return 0;}if ((cstr[i] == '*' && cstr[i+1] == '-') || (cstr[i] == '*' && cstr[i+1] == '+')) {return 0;}if ((cstr[i] == '/' && cstr[i+1] == '-') || (cstr[i] == '/' && cstr[i+1] == '+')) {return 0;}if ((cstr[i] == '+' && cstr[i+1] == '/') || (cstr[i] == '+' && cstr[i+1] == '*')) {return 0;}if ((cstr[i] == '-' && cstr[i+1] == '/') || (cstr[i] == '-' && cstr[i+1] == '*')) {return 0;}if ((cstr[i] == '-' && cstr[i+1] == '-') || (cstr[i] == '-' && cstr[i+1] == '+')) {return 0;}if ((cstr[i] == '+' && cstr[i+1] == '+') || (cstr[i] == '+' && cstr[i+1] == '-')) {return 0;}}if (cstr[length - 1] == '+' || cstr[length - 1] == '-' ||cstr[length - 1] == '*' || cstr[length - 1] == '/') {return 0;}return 1;
}

对于数字和括号的相邻问题,数字后不能直接跟左括号,右括号不能直接跟数字

- (int)numberAndkuoHao:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);int flag = 0;for (int i = 0; i < length; i++) {if ((cstr[i]>= '0' && cstr[i] <= '9') &&cstr[i+1] == '(') {flag++;}if (cstr[i] == ')' && (cstr[i + 1]>= '0' && cstr[i + 1] <= '9')) {flag++;}}if (flag == 0) {return 1;}return 0;
}

对于只有括号没有数字的问题,直接遍历整个字符串如果有数字则标志变量加一,最后判断标志变量

- (int)numberJudge:(NSMutableString*)mutableString {const char* cstr = [mutableString UTF8String];int length = (int)strlen(cstr);int flag = 0;for (int i = 0; i < length; i++) {if (cstr[i]>= '0' && cstr[i] <= '9') {flag++;}}if (flag != 0) {return 1;}return 0;;
}

对于除零问题

if ([self.jieguoStr isEqualToString:@"nan"]) {self.jieguoStr = @"错误";}if ([self.jieguoStr isEqualToString:@"inf"]) {self.jieguoStr = @"错误";}

对于小数点异常处理

int pointFlag = 0;
for (int i = 0; i < resultTop; i++) {if (resultStack[i] == '.') {for (int j = i + 1; resultStack[j] != ' '; j++) {if (resultStack[j] == '.') {pointFlag++;}}}}if (pointFlag != 0) {self.jieguoStr = @"错误";pointFlag = 0;}

对于如何删除多余的零

NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString: self.jieguoStr];NSDecimalNumberHandler *roundHandler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundUp scale:8 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];NSDecimalNumber *roundedNumber = [number decimalNumberByRoundingAccordingToBehavior:roundHandler];self.jieguoStr = [roundedNumber stringValue];

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

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

相关文章

八、互联网技术——物联网

文章目录 一、智慧物联案例分析二、M2M技术三、数据保护综合案例分析一、智慧物联案例分析 智能物流是一种典型的物联网应用。一个物流仓储管理系统架构如下图所示: [问题1] 图中的三层功能:仓库物品识别、网络接入、物流管理中心,分别可对应到物联网基本架构中的哪一层? …

分页查询(关键词: limit)

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 比如现在有一张表emp有15条数据 我想每页只显示5条数据,分3页,这样看起来简捷一些,我该怎么实现呢 语法格式: select */列名 from 表名 limit 初…

Dubbo3应用开发—Dubbo3注册中心(zookeeper、nacos、consul)的使用

Dubbo3注册中心的使用 zookeeper注册中心的使用 依赖引入 <dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-dependencies-zookeeper-curator5</artifactId><version>${dubbo.version}</version><type>p…

三十一、【进阶】B+树的演变过程

1、B树简单介绍 &#xff08;1&#xff09;介绍&#xff1a;B树也属于B树&#xff0c;是B树的变种 &#xff08;2&#xff09;特点&#xff1a;所有的数据都位于叶子节点上&#xff0c;叶子节点上的所有元素形成了一个单项链表 &#xff08;3&#xff09;图示&#xff1a; 2…

「网络安全」SQL注入攻击的真相

前言 点击此处即可获得282G网络安全学习资料 我们生活在数据的黄金时代。有些公司将其分析为更好的自己&#xff0c;有些公司为了获利而进行交易&#xff0c;没有一家公司因其价值而自由放弃 - 对于他们的业务和犯罪分子。 SQL&#xff08;结构化查询语言&#xff09;是一种…

【技术干货】如何通过 DP 实现支持经典蓝牙的联网单品设备与 App 配对

经典蓝牙模块&#xff08;Classic Bluetooth&#xff09;主要用于呼叫和音频传输&#xff0c;所以经典蓝牙最主要的特点就是功耗大&#xff0c;传输数据量大。蓝牙耳机、蓝牙音箱等场景大多采用经典蓝牙&#xff0c;因为蓝牙是为传输声音而设计的&#xff0c;是短距离音频传输的…

钡铼DLT645和IEC104转Modbus协议网关BL120DT:构建智能电力网的关键角色

在电力行业中&#xff0c;DLT645和IEC104转Modbus协议网关已成为重要的通信工具&#xff0c;用于将电力设备的数据和状态信息转换为Modbus协议&#xff0c;以便于远程监控和管理。以下是关于钡铼DLT645和IEC104转Modbus协议网关BL120DT在电力行业应用的案例介绍。 某电力公司需…

自动化项目实战->测试博客系统

1.熟悉项目-->哪些场景容易出现问题 2.针对核心流程设计测试用例(手工测试用例) 3.将手工测试用例转换为自动化测试用例 4.部署到服务器 一、针对核心流程设计测试用例 二、将手工测试用例转换为自动化测试用例 2.1设计自动化测试用例的代码结构 初始化动作:BeforeAll--…

[图论]哈尔滨工业大学(哈工大 HIT)学习笔记23-31

视频来源&#xff1a;4.1.1 背景_哔哩哔哩_bilibili 目录 1. 哈密顿图 1.1. 背景 1.2. 哈氏图 2. 邻接矩阵/邻接表 3. 关联矩阵 3.1. 定义 4. 带权图 1. 哈密顿图 1.1. 背景 &#xff08;1&#xff09;以地球为建模&#xff0c;从一个大城市开始遍历其他大城市并且返回…

SSM - Springboot - MyBatis-Plus 全栈体系(二十一)

第四章 SpringMVC 四、RESTFUL 风格设计和实战 1. RESTFul 风格概述 1.1 RESTFul 风格简介 RESTful&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量…

[架构之路-232]:目标系统 - 纵向分层 - 操作系统 - 数据存储:文件系统存储方法汇总

目录 前言&#xff1a; 一、文件系统存储方法基本原理和常见应用案例&#xff1a; 二、Windows FAT文件系统 2.1 概述 三、Linux EXT文件系统 3.1 基本原理 3.2 索引节点表&#xff08;Inode Table&#xff09; 3.2.1 索引节点表层次结构 3.2.2 间接索引表的大小和表项…

Netty全面了解, 使用,有这一篇就够了

目录 引言&#xff1a; 什么是Netty&#xff1f; Netty和Tomcat有什么区别&#xff1f; 为什么Netty受欢迎&#xff1f; Netty为什么并发高 Netty为什么传输快 为什么说Netty封装好&#xff1f; 使用示例&#xff1a; 步骤1: 添加Netty依赖 步骤2: 创建服务器启动类 步…

OpenResty安装-(基于Nginx的高性能Web平台,可在Nginx端编码业务)

文章目录 安装OpenResty1.安装1&#xff09;安装开发库2&#xff09;安装OpenResty仓库3&#xff09;安装OpenResty4&#xff09;安装opm工具5&#xff09;目录结构6&#xff09;配置nginx的环境变量 2.启动和运行3.备注 安装OpenResty 1.安装 首先你的Linux虚拟机必须联网 …

风储VSG-基于虚拟同步发电机的风储并网系统Simulink仿真

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

小程序中如何核销订单和优惠券

小程序已成为许多商家线上线下开展业务的重要渠道。客户在小程序中下单/领券后&#xff0c;可能需要商家现场扫码核销&#xff0c;例如超市购物、卖票、游乐园等线下场景。下面就介绍小程序中如何核销订单和优惠券。 一、订单核销 订单核销是指商家在小程序中确认顾客已经支付…

开环模块化多电平换流器仿真(MMC)N=6(Simulink仿真)

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

【Vue面试题六】为什么Vue中的 v-if 和 v-for 不建议一起用?

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

socket简介

套接字&#xff08;Socket&#xff09;实质上就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;为应用层进程利网络协议交换数据提供了相应机制。套接字出于承上启下的作用&#xff0c;向上连接应用进程&#xf…

Linux:TCP三握四挥简析

文章目录 1. 前言2. 背景3. TCP连接的建立和断开3.1 TCP协议状态机3.2 TCP的三握四挥3.2.1 TCP 连接建立的三次握手过程分析3.2.1.1 服务端和客户端套接字的创建3.2.1.2 服务端进入 LISTEN 状态3.2.1.3 服务端在 LISTEN 状态等待客户端的 SYN 请求3.2.1.4 客户端向服务端发送 S…

基于虚拟同步发电机控制的双机并联Simulink仿真模型

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