RxSwift官方实例四(计算器)

代码下载

UI

搭建如下图UI:
RxSwift官方实例四(计算器)_第1张图片

实现

计算器逻辑

定义Operator枚举表示基本运算符,如下所示:

/// 基本运算符
enum Operator {
    case addition // 加
    case subtruction // 减
    case multiplication // 乘
    case division // 除
}

extension Operator {
    /// 符号字符串
    var sign: String {
        switch self {
        case .addition:
            return "+"
        case .subtruction:
            return "-"
        case .multiplication:
            return "x"
        case .division:
            return "/"
        }
    }
    
    /// 执行运算
    var perform: (Double, Double) -> Double {
        switch self {
        case .addition:
            return (+)
        case .subtruction:
            return (-)
        case .multiplication:
            return (*)
        case .division:
            return (/)
        }
    }
}

定义CalculatorCommand枚举表示计算器上的所有命令,如下图所示:

/// 计算器命令
enum CalculatorCommand {
    case clear // 输入清除号
    case changeSign // 输入变换符号
    case percent // 输入百分号
    case operation(Operator) // 输入基本运算符
    case equal // 输入等号
    case addNumber(Character) // 输入数字
    case addDoc // 输入小数点
}

定义CalculatorState枚举表示计算器状态:

/// 计算器状态
enum CalculatorState {
    case oneOperand(screen: String) // 一个操作数
    case oneOperandAndOperator(operand: Double, operator: Operator) // 一个操作数和一个操作符
    case twoOperandAndOperator(operand: Double, operator: Operator, screen: String) // 两个个操作数和一个操作符
}

为CalculatorState定义一个计算属性screen表示计算结果:

    /// 屏幕显示数据
    var screen: String {
        switch self {
        case let .oneOperand(screen: screen):
            return screen
        case .oneOperandAndOperator(operand: _, operator: _):
            return CalculatorState.initalScreen
        case let .twoOperandAndOperator(operand: _, operator: _, screen: screen):
            return screen
        }
    }

为CalculatorState定义sign计算属性表示将要执行的操作符:

    /// 屏幕显示操作符
    var sign: String {
        switch self {
        case .oneOperand(screen: _):
            return ""
        case let .oneOperandAndOperator(operand: _, operator: o):
            return o.sign
        case let .twoOperandAndOperator(operand: _, operator: o, screen: _):
            return o.sign
        }
    }

为CalculatorState定义mapScreen函数做数据转换:

    /// 转换屏幕上的数据
    /// - Parameter transform: 转换闭包
    func mapScreen(transform: (String) -> String) -> CalculatorState {
        switch self {
        case let .oneOperand(screen: screen):
            return .oneOperand(screen: transform(screen))
        case let .oneOperandAndOperator(operand: operand, operator: operat):
            return .twoOperandAndOperator(operand: operand, operator: operat, screen: transform(CalculatorState.initalScreen))
        case let .twoOperandAndOperator(operand: operand, operator: operat, screen: screen):
            return .twoOperandAndOperator(operand: operand, operator: operat, screen: transform(screen))
        }
    }

为CalculatorState定义reduce函数来计算计算器状态、结果:

    func reduce(command: CalculatorCommand) -> CalculatorState {
        switch command {
        case .clear:
            return CalculatorState.inital
        case .changeSign:
            return self.mapScreen { (screen) -> String in
                if screen.count == 0 {
                    return "-"
                } else if screen[screen.startIndex] == "-" {
                    let result = screen[screen.index(after: screen.startIndex).. String in
                if screen == CalculatorState.initalScreen {
                    return String(c)
                } else if screen == "-0" {
                    return "-" + String(c)
                } else {
                    return screen + String(c)
                }
            }
        case .addDoc:
            return self.mapScreen(transform: { $0.contains(".") || $0 == CalculatorState.initalScreen ? $0 : $0 + "." })
        }

绑定计算器

代码如下:

        /// 所有操作的Observable数组
        let events: [Observable] = [
            clearButton.rx.tap.map({ CalculatorCommand.clear }),
            changeSignButton.rx.tap.map({ CalculatorCommand.changeSign }),
            percentButton.rx.tap.map({ CalculatorCommand.percent }),
            equalButton.rx.tap.map({ CalculatorCommand.equal }),
            plusButton.rx.tap.map({ CalculatorCommand.operation(Operator.addition) }),
            minusButton.rx.tap.map({ CalculatorCommand.operation(Operator.subtruction) }),
            multiplyButton.rx.tap.map({ CalculatorCommand.operation(Operator.multiplication) }),
            divideButton.rx.tap.map({ CalculatorCommand.operation(Operator.division) }),
            dotButton.rx.tap.map({ CalculatorCommand.addDoc }),
            zeroButton.rx.tap.map({ CalculatorCommand.addNumber("0") }),
            oneButton.rx.tap.map({ CalculatorCommand.addNumber("1") }),
            twoButton.rx.tap.map({ CalculatorCommand.addNumber("2") }),
            threeButton.rx.tap.map({ CalculatorCommand.addNumber("3") }),
            fourButton.rx.tap.map({ CalculatorCommand.addNumber("4") }),
            fiveButton.rx.tap.map({ CalculatorCommand.addNumber("5") }),
            sixButton.rx.tap.map({ CalculatorCommand.addNumber("6") }),
            sevenButton.rx.tap.map({ CalculatorCommand.addNumber("7") }),
            eightButton.rx.tap.map({ CalculatorCommand.addNumber("8") }),
            nineButton.rx.tap.map({ CalculatorCommand.addNumber("9") })
        ]
        
        /// 初始状态
        let initState = CalculatorState.inital
        /// 操作线程
        let scheduler = MainScheduler.instance
        /// 绑定
        Observable.deferred({
            Observable.merge(events)
                .scan(initState) { $0.reduce(command: $1) }
                .subscribeOn(MainScheduler.instance)
                .startWith(initState)
                .observeOn(scheduler)
        }).subscribe(onNext: { (state) in
            self.signLabel.text = state.sign
            self.resultLabel.text = state.screen
        }).disposed(by: bag)

代码分析:

  • 构建一个计算器操作序列的数组,然后使用merge操作符合并为一个序列
  • 使用scan扫描序列,传入计算器初始状态累积来自reduce函数的计算结果
  • 使用startWith设置初始元素,使用observeOn设置线程
  • 最后将计算器状态signscreen绑定到Label上显示,并清理资源

你可能感兴趣的:(RxSwift,基础专辑)