• 【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);
                }];
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

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

    我使用的协议传值进行

    定义协议及协议方法

    @protocol ButttonDelegate <NSObject>
    
    - (void)returnButton:(UIButton*)button;
    
    @end
    
    • 1
    • 2
    • 3
    • 4
    • 5

    定义代理对象

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

    button事件函数触发代理方法

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

    在CalculationViewController中定义协议方法

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

    在CalculationViewController中设置代理对象

     self.calculationView.delegate = self;
    
    • 1

    在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) {
        	//四则运算
        }
    	//
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    		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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    			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--];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    这里使用了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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

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

    三、判错处理

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

    - (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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    - (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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

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

    - (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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

    - (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;;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对于除零问题

    if ([self.jieguoStr isEqualToString:@"nan"]) {
                    self.jieguoStr = @"错误";
                }
                if ([self.jieguoStr isEqualToString:@"inf"]) {
                    self.jieguoStr = @"错误";
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    对于小数点异常处理

    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;
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对于如何删除多余的零

    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];
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    PHP封装CURL类 请求第三方地址
    四、IPSec NAT穿越
    swoole和workman的区别?
    Redis——Linux下安装以及命令操作
    誉天在线项目~ElementPlus图片回显
    2-FreeRTOS编码标准、风格指南
    睿趣科技:抖音小店多久可以做起来
    OpenSea爬取Nft详情全部数据实战
    javaScript---箭头函数和普通函数的区别
    多因素蚁群算法的移动机器人路径规划研究(Matlab代码实现)
  • 原文地址:https://blog.csdn.net/m0_73974920/article/details/133655548