用到的知识点:
- Masonry布局[iOS]-Masonry的使用
- MVC设计模式[iOS]- MVC模式基础
- 栈的思想实现四则运算C语言-栈的四则运算(带小数点和括号)
整体思路:
UI界面的创建:
- 前四行都是四个小按钮,使用四个for循环创建,每次建立一行,最后一行的三个按钮单独建立
- 每个按钮的位置使用Masonry约束,以保证兼容多个机型
代码如下:
for (int i = 1; i <= 4; ++i) {
NSString *string = [NSString stringWithFormat:@"1%d.jpg", i];
_firstGroup = [UIButton buttonWithType:UIButtonTypeCustom];
[_firstGroup setImage:[UIImage imageNamed:string] forState:UIControlStateNormal];
[_firstGroup addTarget:self action:@selector(pressButtonFirst:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_firstGroup];
[_firstGroup mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_offset(self.frame.size.height * 0.380);
make.left.mas_equalTo(self.frame.size.width * (0.035 + 0.241 * (i - 1)));
make.size.mas_equalTo(CGSizeMake(self.frame.size.width * 0.206, self.frame.size.height * 0.095));
}];
_firstGroup.tag = 10 + i;
}
_zeroButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_zeroButton setImage:[UIImage imageNamed:@"0.jpg"] forState:UIControlStateNormal];
[_zeroButton addTarget:self action:@selector(pressButtonZero:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_zeroButton];
_zeroButton.tag = 51;
[_zeroButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_offset(self.frame.size.height * 0.824);
make.left.mas_equalTo(self.frame.size.width * 0.035);
make.size.mas_equalTo(CGSizeMake(self.frame.size.width * 0.447, self.frame.size.height * 0.095));
}];
其中Masonry约束的写法以约束top、left、size三个条件为规范 且每个按钮的事件函数同样写在V中,每次按下按钮时触发事件函数,利用协议传值将相应按钮的tag值传至C中分情况进行操作 四则运算思路:
- 每按下一个按钮就将按钮的相应元素添加至可变字符串中,待按下等号按钮时调用M中的运算函数进行计算
- 首先进行判错处理,如果通过判错处理则进行实际运算过程
- 实际的运算过程是遍历此可变字符串,对每个字符分情况处理
处理逻辑如下: 每次对一个元素进行判断和操作,一共两个栈(一个数字栈,一个符号栈) (1)如果是数字就入数字栈,然后继续操作下一个字符串中的元素 下面是对括号的一些操作: 如果是左括号,就进符号栈,然后继续操作下一个字符串中的元素 如果是右括号,就让符号栈栈顶元素出栈,让数字栈栈顶和次栈顶的两个元素出栈进行运算,并将运算结果入数字栈,一直循环此操作直至遇见符号栈栈顶为左括号为止,遇见左括号后将其出符号栈,并继续操作下一个字符串中的元素 (2)如果是符号: 如果符号栈为空,就直接入符号栈 如果符号栈栈顶的符号的优先级大于当前正在操作的字符串中的元素,就将符号栈栈顶符号出栈,将数字栈栈顶和次栈顶的两个元素出栈,进行运算后将结果入数字栈 如果符号栈栈顶的符号的优先级小于当前正在操作的字符串中的元素,就入符号栈 (3)当字符串中的元素全部遍历完后如果符号栈仍然有元素,就继续从符号栈栈顶出一个元素,从数字栈栈顶出两个元素,计算后将结果入数字栈,循环此操作直至符号栈为空为止
具体代码详见上方超链接中的四则运算博客,实际的计算器编写中可根据需求添加判错 注意的点: OC的栈我们用可变数组来代替,具体代码如下:
- (void) pushNum: (double) num {
if (_numArray.count == 50) {
NSLog(@"进栈失败");
return;
}
[_numArray addObject:[NSString stringWithFormat:@"%f",num]];
return;
}
- (void) pushChar: (char) str {
if (_strArray.count == 50) {
NSLog(@"进栈失败");
return;
}
[_strArray addObject:[NSString stringWithFormat:@"%c", str]];
return;
}
- (double) popNum {
double t;
t = [self backNum:_numArray[_numArray.count - 1]];
[_numArray removeLastObject];
return t;
}
- (char) popChar {
char ch;
ch = [_strArray[_strArray.count - 1] characterAtIndex:0];
[_strArray removeLastObject];
return ch;
}
- (double) topNum {
return [self backNum:_numArray[_numArray.count - 1]];
}
- (char) topChar {
return [_strArray[_strArray.count - 1] characterAtIndex:0];
}
可以看到我们入数字栈的时候实际上入的是字符串,所以需要编写一个函数出数字栈的时候将字符串转为实际的数字,该函数如下:
- (double) backNum:(NSString *) string {
int flag = 0;
double res;
if ([string characterAtIndex:0] == '-') {
flag = 1;
}
if (flag == 0) {
int i = 0;
double x = 0;
while ([string characterAtIndex:i] >= '0' && [string characterAtIndex:i] <= '9' && i < string.length) {
x *= 10;
x += (double)[string characterAtIndex:i] - '0';
++i;
}
if (i < string.length && [string characterAtIndex:i] == '.') {
double d = 0.1;
++i;
while (i < string.length) {
x += ((double)[string characterAtIndex:i] - '0') * d;
d *= 0.1;
++i;
}
}
res = x;
} else {
int i = 1;
double x = 0;
while ([string characterAtIndex:i] >= '0' && [string characterAtIndex:i] <= '9' && i < string.length) {
x *= 10;
x += (double)[string characterAtIndex:i] - '0';
++i;
}
if (i < string.length && [string characterAtIndex:i] == '.') {
double d = 0.1;
++i;
while (i < string.length) {
x += ((double)[string characterAtIndex:i] - '0') * d;
d *= 0.1;
++i;
}
}
res = x;
}
if (flag == 0) {
return res;
} else {
return -res;
}
}
比较符号优先级和计算结果的函数代码如下:
- (NSInteger) compare:(char) str {
if (str == '+' || str == '-') {
return 1;
} else if (str == '*' || str == '/') {
return 2;
} else {
return 0;
}
}
- (double) counter:(double) first :(double) second :(char) strSecond {
double ans = 0.0;
if (strSecond == '+') {
ans = first + second;
} else if (strSecond == '-') {
ans = first - second;
} else if (strSecond == '*') {
ans = first * second;
} else {
ans = first / second;
}
return ans;
}
有了以上函数,我们就可以编写计算的主函数,在主函数中调用以上函数实现计算最终结果的功能了。主函数具体逻辑参考上方四则运算博客
一些细节问题:
我们定义了一个可变字符串,用于存最终的运算结果,最后将屏幕上UI Label的text设置为该可变字符串即可在屏幕上显示最终结果 计算等相关函数写在M中,在C中调用产生效果
|