原来感觉iPhone自带的计算器输入反人类就用swift2自己写了一个,现在正好swift3发布了,应该以后swift语言会稳定很多,所以把计算器改成了3.0。这也算是一个swift语言的小小练习吧,在此再次吐槽一下swift的enum,确实比其他语言好用,但是就不能允许if判断吗?
效果图如下:
我的布局啥的学的实在不行,所以只能在4’屏上显示这样的结果,要是大屏布局就有些难看了。。。
在此写几个自己遇到的问题和解决方法:
我想在同一个键上同时绑定单击和双击事件,然而单击事件会在双击之后响应两次!!!网上也没找到好的而解决方法,只能用笨办法了。。。
/*
clickTimes属性与下面的dealingComplex函数专为ios脑残的单击/双击事件定制,可区分他们
*/
fileprivate var clickTimes = 0 {//记录点击次数
didSet{
if clickTimes == 2 {
brain.popOperand()
displayValue.removeLast()
clickTimes = 0
}
}
}
//有两个输入可能的键调用这个
fileprivate func dealingComplexBtn(_ text:String){
brain.pushOperand(text)
displayValue.append(text)
clickTimes += 1
clickTimes = 0
}
//数字键或操作符单击事件
@IBAction func onNumberOrOperandClicked(_ sender: UIButton) {
let text = sender.currentTitle!
isInputing = true
switch text {
case "^/tan":
dealingComplexBtn("^")
case "log/sin":
dealingComplexBtn("log")
case "ln/cos":
dealingComplexBtn("ln")
case "./e":
dealingComplexBtn(".")
case "0/pi":
dealingComplexBtn("0")
default:
brain.pushOperand(text)
displayValue.append(text)
}
}
//操作符双击事件,将点击次数置为1在把单击多出来的输入弹出
@IBAction func onOperandDoubleClicked(_ sender: UIButton) {
let text = sender.currentTitle!
clickTimes = 1
brain.popOperand()
displayValue.removeLast()
isInputing = true
switch text {
case "^/tan":
brain.pushOperand("tan")
displayValue.append("tan")
case "log/sin":
brain.pushOperand("sin")
displayValue.append("sin")
case "ln/cos":
brain.pushOperand("cos")
displayValue.append("cos")
case "./e":
brain.pushOperand("e")
displayValue.append("e")
case "0/pi":
brain.pushOperand("pi")
displayValue.append("pi")
default:
break
}
}
至于运算逻辑,就是把输入的单个数字先拼接成完整的数字,例如20.19是一次输入2 0 . 1 9,通过parseFormula()函数将它们转化为20.19.
然后将1+2*(3-1)这样的前缀表达式转化为1231-*+这样的后缀表达式,后缀表达式的优势在于可以直接通过栈的一次调用运算得出结果.
拼接数字的函数为:
//算式解析,将数字拼在一起,将E与PI替换成数字
fileprivate func parseFormula() -> Bool {
//首先判断括号是否一一匹配
var parentsis = 0
for op in preStack {
switch op {
case .parenthese(let direction):
if direction {
parentsis=parentsis-1
}
else{
parentsis=parentsis+1
}
default:break
}
}
if parentsis != 0 {
return false
}
//接着解析数字
var tempStack = [Operation]()
var buffer:String = ""
for op in preStack {
switch op {
case .operand(let value):
buffer += "\(Int(value))"
continue
case .dot:
buffer += "."
continue
case .e:
tempStack.append(Operation.operand(M_E))
case .pi:
tempStack.append(Operation.operand(M_PI))
default:
if !buffer.isEmpty{
if let value = Double(buffer) {
tempStack.append(Operation.operand(value))
buffer = ""
}
else {
return false
}
}
tempStack.append(op)
}
}
if let value = Double(buffer) {
tempStack.append(Operation.operand(value))
}
preStack = tempStack
return true
}
将前缀表达式转换为中缀表达式的函数为:
//前缀表达式转中缀表达式
fileprivate func preToIn(){
var temp = [Operation]()
var unaryOperator:Operation?
for op in preStack {
switch op {
case .operand(_):
inStack.append(op)
if unaryOperator != nil {
inStack.append(unaryOperator!)
unaryOperator=nil
}
case .unaryOperator(_, _):
unaryOperator = op
case .binaryOperator(_, _):
if !temp.isEmpty {
lable: while temp.last!.compareTo(op)>=0 {
switch temp.last! {
case .parenthese(false):
break lable
default:
inStack.append(temp.removeLast())
}
if temp.isEmpty {
break
}
}
}
temp.append(op)
case .parenthese(false):
temp.append(op)
case .parenthese(true):
lable: while true {
switch temp.last! {
case .parenthese(false):
temp.removeLast()
break lable
default:
inStack.append(temp.removeLast())
}
}
default:
break
}
}
if !temp.isEmpty {
while true {
if let _ = temp.last {
inStack.append(temp.removeLast())
}
else{
break
}
if !temp.isEmpty {
break
}
}
}
}
其中的preStack是前缀表达式的栈,在这里有一个var unaryOperator:Operation?
这是为了解决单目操作符的问题.
计算中缀表达式的函数为:
//计算中缀表达式
fileprivate func calculateIn() -> String?{
var operandStack = [Double]()
for op in inStack {
switch op {
case .operand(let value):
operandStack.append(value)
case .unaryOperator(_, let unaryOperator):
operandStack.append(unaryOperator(operandStack.removeLast()))
case .binaryOperator(_, let binaryOperator):
let rightValue = operandStack.removeLast()
let leftValue = operandStack.removeLast()
operandStack.append(binaryOperator(leftValue,rightValue))
default:
break
}
}
if operandStack.isEmpty {
return nil
}
else{
return operandStack.last?.description
}
}
学艺不精,布局没弄好,代码写的也不够精炼,希望有大神能够斧正一下.
源码在此