irpas技术客

【iOS】—— 仿写计算器项目总结_zxb10

网络 1866

仿写计算器

在完成这次仿写任务时,和以前所写的项目最大的区别时首次运用到了MVC模式和Masonry界面,并且在计算器使用的过程中运用了很多的算法知识,在整个过程中会出现特别多的error,以及很神奇的错误。

View

先来看界面:

利用Masonry布局,保证这个比例在每个手机上都能正确显示,在创建按钮的时候利用循环创建,把0这个大按钮单独拿出来创建,代码如下:

- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; self.backgroundColor = [UIColor blackColor]; _firstarray = [NSArray arrayWithObjects:@"0", @"0", @"0", @".", @"=", @"1", @"2", @"3", @"+", @"4", @"5", @"6" , @"-", @"7", @"8", @"9", @"*", @"AC", @"(", @")", @"/", nil]; _label = [[UILabel alloc] init]; _label.backgroundColor = [UIColor blackColor]; _label.textColor = [UIColor whiteColor]; _label.textAlignment = NSTextAlignmentRight; _label.text = @"0"; _label.font = [UIFont systemFontOfSize:0.15 * Width]; [self addSubview:_label]; [_label mas_makeConstraints:^(MASConstraintMaker* make) { make.bottom.equalTo(self).offset(-((smallWidth + 13) * (5 + 1)) + 20); make.left.equalTo(self).offset(13 + (smallWidth + 13) * 0); make.width.equalTo(@(Width - 26)); make.height.equalTo(@smallWidth); }]; for (int i = 0; i < 5; i++) { for (int j = 0; j < 4; j++) { _smallbutton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; _smallbutton.titleLabel.font = [UIFont systemFontOfSize:0.115 * Width]; _smallbutton.tintColor = [UIColor whiteColor]; if (i == 4 && j <= 2) { _smallbutton.titleLabel.font = [UIFont systemFontOfSize:Width * 0.1]; _smallbutton.tintColor = [UIColor blackColor]; } _smallbutton.layer.cornerRadius = smallWidth / 2; [self addSubview:_smallbutton]; if ((i == 0 && j == 0) || (i == 0 && j == 1)) { continue; } else { _smallbutton.tag = i * 4 + j + 1; [_smallbutton mas_makeConstraints:^(MASConstraintMaker* make) { make.bottom.equalTo(self).offset(-((smallWidth + 13) * (i + 1)) + 40); make.left.equalTo(self).offset(13 + (smallWidth + 13) * j); make.width.equalTo(@smallWidth); make.height.equalTo(@smallWidth); }]; } if (i >= 0 && i < 4 && j < 3) { [_smallbutton setBackgroundColor:[UIColor colorWithRed:(85.0f / 256.0f) green:(85.0f / 256.0f) blue:(85.0f / 256.0f) alpha:1]]; } else if (j == 3) { [_smallbutton setBackgroundColor:[UIColor colorWithRed:(239.0f / 256.0f) green:(143.0f / 256.0f) blue:(50.0f / 256.0f) alpha:1]]; } else { [_smallbutton setBackgroundColor:[UIColor colorWithRed:(170.0f / 256.0f) green:(170.0f / 256.0f) blue:(170.0f / 256.0f) alpha:1]]; } [_smallbutton setTitle:_firstarray[_smallbutton.tag] forState:UIControlStateNormal]; [_smallbutton addTarget:self action:@selector(buttonreturn:) forControlEvents:UIControlEventTouchUpInside]; } } _smallbutton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; _smallbutton.layer.cornerRadius = smallWidth / 2; _smallbutton.tintColor = [UIColor whiteColor]; [self addSubview:_smallbutton]; _smallbutton.tag = 1; [_smallbutton mas_makeConstraints:^(MASConstraintMaker* make) { make.bottom.equalTo(self).offset(-((smallWidth + 13) * (0 + 1)) + 40); make.left.equalTo(self).offset(13 + (smallWidth + 13) * 0); make.width.equalTo(@(smallWidth * 2 + 13)); make.height.equalTo(@smallWidth); }]; [_smallbutton setBackgroundColor:[UIColor colorWithRed:(85.0f / 256.0f) green:(85.0f / 256.0f) blue:(85.0f / 256.0f) alpha:1]]; _smallbutton.titleLabel.font = [UIFont systemFontOfSize:0.115 * Width]; [_smallbutton setTitle:_firstarray[_smallbutton.tag] forState:UIControlStateNormal]; [_smallbutton addTarget:self action:@selector(buttonreturn:) forControlEvents:UIControlEventTouchUpInside]; return self; }

在完成了按钮以及label的初始化后,View的工作就基本完成了,也就是最简单的一步完成,在完成按钮后,就要为按钮添加点击事件,这里一定要注意的是,按钮的点击事件在MVC模式里,是不允许添加在View里的,要将点击事件添加在Controller里。这样的话就一定要给每个button赋tag值,然后将button传值到controller里面,在controller里面完成事件函数。

Controller

在控制计算器输入合理的过程中,我在Controller里控制输入的时候就有些限制,还有一些弹出错误放在了Modal里,首先控制小数点在一个数值中只能出现一次,记录小数点状态变了之后,再点击就没有事件,还有防止连续输入符号,和小数点的控制方式类似。

很重要的一点是括号问题,括号只能先左再右,就令一个变量,记录左括号的数量,当输入左括号时,该变量++,输入右括号时,该变量–,当该变量为0时,不能输入右括号。

// 记录小数点状态 int pointFlag = 0; // 防止连续输入符号 int secondFlag = 0; // 记录等于号状态 int equalFlag = 0; // 记录数字后再输入小数点 int numpoint = 0; //记录左括号数量 int leftbrackets = 0; - (void)Chubutton:(UIButton *)button { //NSLog(@"%ld",(long)button.tag); if (button.tag == 17) { //AC //[_MainArray removeAllObjects]; _MainString = nil; _MainString = [[NSMutableString alloc] init]; self.mainview.label.text = @"0"; pointFlag = 0; secondFlag = 0; equalFlag = 0; leftbrackets = 0; } else if (button.tag == 1) { //0 // [_MainArray addObject:button.titleLabel.text]; [_MainString appendString:button.titleLabel.text]; self.mainview.label.text = _MainString; secondFlag = 0; numpoint = 0; } else if ((button.tag <= 7 && button.tag >= 5) || (button.tag <= 11 && button.tag >= 9) || (button.tag <= 15 && button.tag >= 13)) { //9个数字 //[_MainArray addObject:button.titleLabel.text]; [_MainString appendString:button.titleLabel.text]; self.mainview.label.text = _MainString; secondFlag = 0; numpoint = 0; } else if (button.tag == 3) { //小数点 if (numpoint == 0 && pointFlag == 0) { //[_MainArray addObject:button.titleLabel.text]; [_MainString appendString:button.titleLabel.text]; self.mainview.label.text = _MainString; pointFlag = 1; } else { } } else if (button.tag == 20 || button.tag == 8 || button.tag == 12 || button.tag == 16) { //四个运算符 if (secondFlag == 0) { pointFlag = 0; secondFlag = 1; numpoint = 1; //[_MainArray addObject:button.titleLabel.text]; [_MainString appendString:button.titleLabel.text]; self.mainview.label.text = _MainString; } else { } } else if (button.tag == 4) { //等号 //[_MainArray addObject:button.titleLabel.text]; //[_MainString appendString:button.titleLabel.text]; self.mainview.label.text = _MainString; [_MainString replaceOccurrencesOfString:@")(" withString:@")*(" options:NSLiteralSearch range:NSMakeRange(0, [_MainString length])]; const char *cstring = [_MainString UTF8String]; NSMutableString *newstring = [NSMutableString stringWithFormat:@"%@", [self.mainmodel transform:cstring]]; NSLog(@"%@",newstring); if ([newstring isEqualToString:@"error"] || [newstring isEqualToString:@"inf"]) { newstring = [NSMutableString stringWithFormat:@"error"]; } else { newstring = [NSMutableString stringWithFormat:@"%@", @(newstring.floatValue)]; } NSLog(@"%@",newstring); self.mainview.label.text = newstring; _MainString = nil; _MainString = [[NSMutableString alloc] init]; if ([newstring isEqualToString:@"error"] || [newstring isEqualToString:@"inf"]) { } else { [_MainString appendString:newstring]; } pointFlag = 0; secondFlag = 0; equalFlag = 0; leftbrackets = 0; } else if (button.tag == 18) { //左 // [_MainArray addObject:button.titleLabel.text]; leftbrackets++; [_MainString appendString:button.titleLabel.text]; self.mainview.label.text = _MainString; secondFlag = 0; } else if (button.tag == 19) { //右 //[_MainArray addObject:button.titleLabel.text]; if (leftbrackets != 0) { [_MainString appendString:button.titleLabel.text]; self.mainview.label.text = _MainString; leftbrackets--; } else { } } }

这里用到的方法将oc字符串转为c字符串,便于对每一个字符的遍历。

const char *cstring = [_MainString UTF8String]; Model

Model部分的代码是最难的,在学习之前得先搞懂用栈如何进行四则运算,可以看之前博客:c语言四则运算

除此之外,在计算中会遇到括号,这时候就需要把中缀表达式转化为后缀表达式,然后再进行计算,思想参考大佬博客

但是还需要注意,上述的方法只能进行整数的运算,在写完计算器之后我才意识到这个问题,其实只需要把int类型转化为double类型,然后在读取的时候,遇到小数点,后面的数值??0.1的位数次方,然后加进去即可。

在model端也要进行很多controller端没有进行完的判错,其中包括左括号前不能直接接数字,右括号后不能直接接数字,左右括号数量不相等等问题。

代码:

- (double)Count:(double)x :(char)ch :(double)y { if (ch == '+') return x + y; else if(ch == '-') return x - y; else if(ch == '*') return 1.0 * x * y; else if(ch == '/') return 1.0 * x / y; else return -1; } - (NSString *)transform:(const char *)arr { int i; if (arr[strlen(arr) - 1] == '+' || arr[strlen(arr) - 1] == '-' || arr[strlen(arr) - 1] == '*' || arr[strlen(arr) - 1] == '/') { NSString *errorstring = [NSString stringWithFormat:@"error"]; return errorstring; } int leftbrackets = 0, rightbrackets = 0; for (i = 0; i < strlen(arr); i++) { if ((arr[i] == '(' && (arr[i + 1] == '*' || arr[i + 1] == '/')) || ((arr[i] == ')') && ((arr[i - 1] == '+') || (arr[i - 1] == '-') || (arr[i - 1] == '*') || (arr[i - 1] == '/')))) { NSString *errorstring = [NSString stringWithFormat:@"error"]; return errorstring; } if ((arr[i] == '(' && (arr[i - 1] <= '9' && arr[i - 1] >= '0'))||(arr[i] == ')' && (arr[i + 1] <= '9' && arr[i + 1] >= '0'))) { NSString *errorstring = [NSString stringWithFormat:@"error"]; return errorstring; } if (arr[i] == '(') { leftbrackets++; } else if (arr[i] == ')') { rightbrackets++; } } if (leftbrackets != rightbrackets) { NSString *errorstring = [NSString stringWithFormat:@"error"]; return errorstring; } double x = 0.0; int flag = 0; int f = 0; double numStack[1000]; int numTop = -1; char symbolStack[100]; int symbolTop = -1; int dian = 0; for (i = 0; i < strlen(arr); i++) { if ((arr[i] >= '0' && arr[i] <= '9') || arr[i] == '.') { if (arr[i] == '.') { dian = 1; continue; } if (dian == 0) { x = x * 10 + (arr[i] - '0'); flag = 1; } else { x = x + (arr[i] - '0') * pow(0.1, dian); //flag = 1; dian++; } } else { if (flag == 1) { if (f == 1) { x = (-1) * x; f = 0; } numStack[++numTop] = x; //NSLog(@"%lf niubi",x); x = 0; flag = 0; } if (arr[i] == '(' || arr[i] == '*' || arr[i] == '/') { if ((arr[i] == '*' || arr[i] == '/') && (symbolStack[symbolTop] == '*' || symbolStack[symbolTop] == '/')) { numStack[numTop-1] = [self Count:numStack[numTop-1] :symbolStack[symbolTop] :numStack[numTop]]; numTop--; symbolTop--; } symbolStack[++symbolTop] = arr[i]; } if (arr[i] == ')') { while (symbolStack[symbolTop] != '(') { numStack[numTop - 1] = [self Count:numStack[numTop - 1] :symbolStack[symbolTop] :numStack[numTop]]; numTop--; symbolTop--; } if (symbolStack[symbolTop] == '(') { symbolTop = symbolTop - 1; } } if (arr[i] == '+' || (arr[i] == '-' && arr[i - 1] != '(')) { if ((arr[i] == '+' || arr[i] == '-') && (symbolStack[symbolTop] == '+' || symbolStack[symbolTop] == '-')) { numStack[numTop-1] = [self Count:numStack[numTop-1] :symbolStack[symbolTop] :numStack[numTop]]; numTop--; symbolTop--; } if ((symbolStack[symbolTop] != '*' && symbolStack[symbolTop]!='/') || symbolTop == -1) { symbolStack[++symbolTop] = arr[i]; } else { numStack[numTop - 1] = [self Count:numStack[numTop-1] :symbolStack[symbolTop] :numStack[numTop]]; NSLog(@"%f %c %f",numStack[numTop-1] ,symbolStack[symbolTop] ,numStack[numTop]); numTop--; symbolTop--; i = i - 1; } } if (arr[i] == '-' && arr[i-1] == '(') { f = 1; } dian = 0; } } if (arr[strlen(arr)-1] >= '0' && arr[strlen(arr)-1] <= '9') { numStack[++numTop]=x; } while (symbolTop != -1) { numStack[numTop - 1] = [self Count:numStack[numTop-1] :symbolStack[symbolTop] :numStack[numTop]]; //NSLog(@"%f %c %f %d %d",numStack[numTop-1] ,symbolStack[symbolTop] ,numStack[numTop],numTop,symbolTop); numTop--; symbolTop--; } NSString *string = [NSString stringWithFormat:@"%.6f", numStack[numTop]]; //NSLog(@"%@",string); return string; }

在完成项目后遇到了一个问题,当计算结果为9.3或9.2的时候,会显示如下:

为了解决这一问题,在代码中输出计算结果:

其中我用到了doubleValue方法来去掉结果后面多余的0,结果发现,在运行完这一代码后不但没有去掉后面的0,而且在数值发生了改变,最后在测试中发现是单精度和双精度的问题,将doubleValue改成floatValue即可。


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #iOS #仿写计算器项目总结