swift3版的iOS计算器

博主分享了使用Swift3重构的iOS计算器应用,探讨了Swift的enum语法,并指出其不支持if判断的困扰。计算器在4英寸屏幕上显示,但在大屏设备上布局不太理想。文章列举了在绑定单击和双击事件时遇到的问题,以及如何处理数字输入和运算逻辑,包括将前缀表达式转换为后缀表达式以简化计算。源码可供参考,期待改进意见。
摘要由CSDN通过智能技术生成

原来感觉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
        }
    }

学艺不精,布局没弄好,代码写的也不够精炼,希望有大神能够斧正一下.
源码在此

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值