【iOS】计算器仿写

news2024/11/30 14:53:17

文章目录

  • 前言
  • 一、构建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.coloradmin.cn/o/1095700.html

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

相关文章

Linux系统编程:文件描述符以及IO多路复用

书接上回&#xff0c;我们之前学习的文件系统编程都是在内存空间中的文件流&#xff08;用户态文件缓冲区&#xff09;内进行操作的&#xff0c;比如使用的fopen、fclose、fread和fwrite等等都是库函数&#xff0c;并没有用到内核态的功能&#xff08;实际上库函数中调用的是内…

hive排序

目录 order by (全局排序asc ,desc) sort by(reduce 内排序) Distribute by(分区排序) Cluster By&#xff08;当 distribute by 和 sorts by 字段相同时 &#xff0c;可以使用 &#xff09; order by (全局排序asc ,desc) INSERT OVERWRITE LOCAL DIRECTORY /home/test2 …

Ubuntu系统下配置安装区块链Hyperledger Fabric(新手小白篇)

有些安装过程比较简单的&#xff0c;不会详细赘述。主要还是集中在Hyperledger Fabric的配置上。 本篇主要介绍在Ubuntu系统上安装Hyperledger Fabric的过程。这里使用的Ubuntu&#xff1a;16.04 LTS。 1. Git安装 Git工具安装命令如下&#xff1a; sudo apt update sudo ap…

基于主动移频法与AFD孤岛检测的单相并网逆变器matlab仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 仿真模型 算法介绍 (1)仿真模型由单相电网、逆变器、滤波环节、PI控制器、PWM生成器、锁相环、AFD控制器s函数、测量模块等构成&#xff1b; (2)采用主动移频法(AFD)进行孤岛检测&#xff1b; (3)相应速度…

MATLAB——径向基神经网络预测程序

欢迎关注公众号“电击小子程高兴的MATLAB小屋” %% 学习目标&#xff1a;径向基神经网络 %% 可以以任意精度逼近任意连续函数 clear all; close all; P1:10; T[2.523 2.434 3.356 4.115 5.834 6.967 7.098 8.315 9.387 9.928]; netnewrbe(P,T,2); %建立精确的径向基…

语料库应用入门讲座

语料库应用入门讲座 引言 主要介绍语料库的概念、功能、意义和基础的方法。主要包括&#xff1a; 1. 什么是语料库&#xff1f;语料库有什么作用&#xff1f; 2. 语料库的分类有哪些&#xff1f; 3. 语料库有什么功能&#xff1f; 4. 常见的语料库工具有哪些&#xff1f; …

Spring源码解析——Spring事务是怎么通过AOP实现的?

正文 此篇文章需要有SpringAOP基础&#xff0c;知道AOP底层原理可以更好的理解Spring的事务处理。最全面的Java面试网站 自定义标签 对于Spring中事务功能的代码分析&#xff0c;我们首先从配置文件开始人手&#xff0c;在配置文件中有这样一个配置&#xff1a;<tx:annot…

vue3-admin-plus框架

拉取 git clone https://github.com/jzfai/vue3-admin-plus.git 安装pnpm npm -g i pnpm7.9.0 node版本&#xff08;&#xff09; 使用nvm改node版本为v16.10.0 v16.10.0 先安装依赖 pnpm install esbuild0.15.18 然后再安装其他依赖 pnpm i 直接安装依赖pnpm i会报错 这个错误…

如何用精准测试来搞垮团队?

测试行业每年会冒出来一些新鲜词&#xff1a;混沌工程、精准测试、AI测试…… 这些新概念、新技术让我们感到很焦虑&#xff0c;逼着自己去学习和了解这些新玩意&#xff0c;担心哪一天被淘汰掉。 以至于给我这样的错觉&#xff0c;当「回归测试」、「精准测试」这两个词摆在一…

【Java 进阶篇】JavaScript 事件详解

在本篇博客中&#xff0c;我们将深入探讨JavaScript事件&#xff0c;这是网页交互的核心。我们将从什么是事件开始&#xff0c;然后逐步介绍事件的类型、如何注册事件、事件处理程序、事件对象以及事件冒泡等相关内容。最终&#xff0c;我们将提供大量的示例代码来帮助您更好地…

【LeetCode】每日一题两数之和寻找正序数组的中位数找出字符串中第一个匹配项的下标在排序数组中查找元素的第一个和最后一个位置

主页点击直达&#xff1a;个人主页 我的小仓库&#xff1a;代码仓库 C语言偷着笑&#xff1a;C语言专栏 数据结构挨打小记&#xff1a;初阶数据结构专栏 Linux被操作记&#xff1a;Linux专栏 LeetCode刷题掉发记&#xff1a;LeetCode刷题 算法&#xff1a;算法专栏 C头…

二、K8S之Pods

Pod 一、概念 K8S作为一个容器编排管理工具&#xff0c;它可以自动化容器部署、容器扩展、容器负载均衡等任务&#xff0c;并提供容器的自愈能力等功能。在Kubernetes中&#xff0c;Pod是最基本的调度单元&#xff0c;它是一组共享存储和网络资源的容器集合&#xff0c;通常是…

Java集合类ArrayList的应用-杨辉三角的前n行

目录 一、题目 杨辉三角 二、题解 三、代码 四、总结 一、题目 题目链接&#xff1a;https://leetcode.cn/problems/pascals-triangle/description/ 杨辉三角 题目描述&#xff1a;给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨…

充换电企业开迈斯低成本提升线上应用稳定性的最佳实践

作者&#xff1a;开迈斯新能源 开迈斯新能源科技有限公司于 2019 年 5 月 16 日成立&#xff0c;目前合资股东分别为大众汽车&#xff08;中国&#xff09;投资有限公司、中国第一汽车股份有限公司、一汽-大众汽车有限公司[增资扩股将在取得适当监督&#xff08;包括反垄断&am…

vh、vw、vmin、vmax

1、分别是什么&#xff1f; vh:指屏幕可见视窗的高&#xff0c; vw:指屏幕可见视窗的宽&#xff0c; vmin:vh和vw之间选较小的值&#xff0c; vmax:vh和vw之间选较大的值。 2、和百分比的区别 百分比时基于父元素的宽高&#xff0c;而vh\vw\vmin\vmax基于屏幕可见视图的宽…

【MySQL JDBC】使用Java连接MySQL数据库

一、什么是JDBC&#xff1f; 理解API的概念 API&#xff1a;Application Programing Interface -- 应用程序编程接口写好一个程序&#xff0c;这个程序需要给别人提供哪些功能&#xff1f;这些功能就是通过一些 函数/类 这样的方式来提供的。例如 Random、Scanner、ArrayList..…

2.Python-用Flask框架创建一个简单的Web程序

怎么安装Flask框架 在终端输入以下命令&#xff1a; pip install flask 验证flask安装&#xff1a; flask --version 编写app.py文件 app文件py如下&#xff1a; #导入flask框架中的两个模块 #Flask允许创建一个Flask应用实例&#xff0c;处理路由、请求和响应等功能 #render…

zookeeper应用场景(二)

单机环境下可以利用jvm级别的锁&#xff0c;比如synchronized、Lock等来实现锁&#xff0c;如果是多机部署就需要一个共享数据存储区域来实现分布式锁 一、分布式锁实现方式 1、基于数据库实现分布式锁 可以用数据库唯一索引来实现 2、基于redis实现分布式锁 redis实现的分…

测试除了点点点,还有哪些内容呢?

今天和一个网友讨论了一下关于互联网行业中测试的情况&#xff0c;希望能够了解现在的互联网行业主要的测试工作内容。小编根据以往的工作经历和经验情况&#xff0c;来做一个总结和整理。 1、岗位分类 现在的岗位划分主要是分为两大类&#xff1a;测试工程师 和 测试开发工程…

1、验证1101序列(Moore)

题目要求&#xff1a; 用Moore型状态机验证1101序列。 题目描述&#xff1a; 用使用状态机验证1101序列&#xff0c;注意&#xff1a;允许重复子序列。如图 端口描述&#xff1a; module moore_1101(input clk,//时钟信号input clr,//reset复位信号&#xff0c;高电平有效in…