Swiftで遊ぼう! - 214 - Developing iOS 8 Apps with Swift - More Xcode and Swift, MVC - 時間はかかるよ
Swiftで遊ぼう!の古い記事-> Life-LOG OtherSide
Calculatorプロジェクトのコードの続き。
昨日は、下のトピックに話題が入る前に疲れて終わっちゃいました(^_^;)
- switch
- type型としての関数
- 関数をあっという間に定義するクロージャー
switchの説明は、operatorボタン(× ÷、+、−)で共通したアクションメソッドoperateを利用するところに出てくる。
次のコードはswitchの使用例で、このアクションメソッドの中で計算させている。コーディングしているのは「×」だけで、他のオペレーションはすべてコピペしているだけなんで、例えばという話でイメージしてください。これはあまりスマートなコーディングじゃないですよね。
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! if userIsInTheMiddleOfTypingNumber { enter() } switch operation { case "×": if operandStack.count >= 2 { displayValue = operandStack.removeLast() * operandStack.removeLast() enter() } case "÷": if operandStack.count >= 2 { displayValue = operandStack.removeLast() * operandStack.removeLast() enter() } case "+": if operandStack.count >= 2 { displayValue = operandStack.removeLast() * operandStack.removeLast() enter() } case "−": if operandStack.count >= 2 { displayValue = operandStack.removeLast() * operandStack.removeLast() enter() } default: break } }
ここで共通部分を関数として取り出すと次のようにできる。
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! if userIsInTheMiddleOfTypingNumber { enter() } switch operation { case "×": performOperation(multiply) // case "÷": // case "+": // case "−": default: break } } func performOperation(operation:(Double, Double) -> Double) { if operandStack.count >= 2 { displayValue = operation(operandStack.removeLast(), operandStack.removeLast()) enter() } } func multiply(op1: Double, op2: Double) -> Double { return op1 * op2 }
実はこのようにメソッドの引数にメソッドを渡すというやり方はSwiftで一般的で、この使い方を自由に使えないと後で苦労するだろう。でも、頭の悪い私にはまだ自分で使えそうにない(T_T) しかし、ここから次のクロージャーに発展していく。
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! if userIsInTheMiddleOfTypingNumber { enter() } switch operation { case "×": performOperation{(op1: Double, op2: Double) -> Double in return op1 * op2 } // case "÷": // case "+": // case "−": default: break } } func performOperation(operation:(Double, Double) -> Double) { if operandStack.count >= 2 { displayValue = operation(operandStack.removeLast(), operandStack.removeLast()) enter() } }
そしてクロージャーの真骨頂は次のように省略するのが一般的だ。この変化はThe Swift Programming Language本でしっかり学んでおこう。
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! if userIsInTheMiddleOfTypingNumber { enter() } switch operation { case "×": performOperation{ $0 * S1} case "÷": performOperation{ $1 / S0} case "+": performOperation{ $0 + S1} case "−": performOperation{ $1 - S0} default: break } } func performOperation(operation:(Double, Double) -> Double) { if operandStack.count >= 2 { displayValue = operation(operandStack.removeLast(), operandStack.removeLast()) enter() } }
これがクロージャ、関数を引数として渡す時に有用ですね。
もう一つだけ、クロージャーのところで注意点が示されている。
Main.storyboard上でシフトキーを押して「×」「÷」「+」「−」の4つのボタンを選択してからOpt + ドラッグして右横にボタンのコピーを作ってください。
上3つのボタンはタイトルを消して(消してボタンを消さないように、後でレイアウト調整で使います)、一番下のボタンを「√(ルート)」に変更してください。
ボタンが増えたので、switchのcaseを1つ増やします。
case "√": performOperation{ sqrt($0) }
しかし、よく見て下さい。このperformOperation()では引数を1つしか与えていないのでエラーになります。
じゃあどうするか?
答えは引数を1つだけ受け取る同じ名前のメソッドを用意すれば、Swiftが自動で判断してくれるんです。凄いですね。
@IBAction func operate(sender: UIButton) { let operation = sender.currentTitle! if userIsInTheMiddleOfTypingNumber { enter() } switch operation { case "×": performOperation{ $0 * $1 } case "÷": performOperation{ $1 / $0 } case "+": performOperation{ $0 + $1 } case "−": performOperation{ $1 - $0 } case "√": performOperation{ sqrt($0) } default: break } } func performOperation(operation:(Double, Double) -> Double) { if operandStack.count >= 2 { displayValue = operation(operandStack.removeLast(), operandStack.removeLast()) enter() } } func performOperation(operation: Double -> Double) { if operandStack.count >= 1 { displayValue = operation(operandStack.removeLast()) enter() } }
今日はここまで。