Swiftを解説していきます(2)


```
import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var display: UILabel!
    
    var userIsInTheMiddleOfTypingANumber: Bool = false
 
    @IBAction func appendDigit(sender: UIButton) {
        let digit = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber{
            display.text = display.text! + digit
        }else{
            display.text = digit
            userIsInTheMiddleOfTypingANumber = true
        }
        
        println("digit = \(digit)")
    }

}
```
上のコードのUILabel!をUILabel?にしても、Optionalである。
だが、エラーが出る。
そこで、display.textをdisplay!.textにすると、エラーが治る。
これはどういうことだろうか。

http://tea-leaves.jp/swift/content/%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%9E%8B

ここに詳しい説明が載っている。
つまり、!を使っていた場合は「暗黙的なOptional」を使っていたのである。暗黙的であるため、自動的にUnwrapされていたわけだ。
?に変えたことによって、明示的なOptionalに変わったため、display!.textの!が必要になったのである。

コードは以下のようになった

```

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var display: UILabel?
    
    var userIsInTheMiddleOfTypingANumber: Bool = false
 
    @IBAction func appendDigit(sender: UIButton) {
        let digit = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber{
            display!.text = display!.text! + digit
        }else{
            display!.text = digit
            userIsInTheMiddleOfTypingANumber = true
        }
        
        println("digit = \(digit)")
    }

}
```

では、コードを戻しておこう。

前の回の続きなので、３ボタンを複製してEnterキーを作ろう。
Edit→Emoji&Symbolsでenterを入れると、Enterが出てくるので、それを使おう。
次にこれをAction接続する。Name:enterで、ArgumentはNoneだ。

そうすると、Enterが文字盤に出てしまう。なので、EnterのappendDigitに対する接続を切っておこう。

以下のような図になる。

![Kobito.Cpjurr.png](https://qiita-image-store.s3.amazonaws.com/0/53172/d08e95c7-c47f-b985-e37e-5f8a61f830ec.png "Kobito.Cpjurr.png")

では、以下のコードをプロパティに加えよう

```
var operandStack:Array<Double> = Array<Double>()
```
これは、ジェネリック型の一つで、Doubleを要素とした配列を構成する。= Array<Double>()で初期化をしないとエラーが出る。
これで全部のコードは以下のようになる。

```
import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var display: UILabel!
    
    var userIsInTheMiddleOfTypingANumber: Bool = false
 
    @IBAction func appendDigit(sender: UIButton) {
        let digit = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber{
            display.text = display.text! + digit
        }else{
            display.text = digit
            userIsInTheMiddleOfTypingANumber = true
        }
        
        println("digit = \(digit)")
    }
    
    var operandStack:Array<Double> = Array<Double>()
    @IBAction func enter() {
        userIsInTheMiddleOfTypingANumber = false
    }
}
```

operandStackに表示された値を入力するために以下のようにします

```
    @IBAction func enter() {
        userIsInTheMiddleOfTypingANumber = false
        operandStack.append(display.text!)
    }
```
するとエラーが出ますね。operandStackはDoubleなのに対し、display.text!はStringだからです。

そこで、以下のようにします

```
    @IBAction func enter() {
        userIsInTheMiddleOfTypingANumber = false
        operandStack.append(self.displayValue)
        println("operandStack = \(operandStack)")
    }
    
    var displayValue: Double {
        get{
            return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
        }
        set{
            display.text = "\(newValue)"
            userIsInTheMiddleOfTypingANumber = false
        }
    }
```
getの方ではNSNumberFormatter()のnumberFromStringによってdisplay.textをdoubleに変えていますね。
setの方では、display.text = "\(newValue)"によって、doubleをStringに変えてdisplay.textに代入しています。

次に、✖️ボタンをつけて、Action接続します。typeはUIButtonでやります。
appendDigitへの接続は切っておくことですね。

以下のようなコードになりました

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
            case "×":
                if operandStack.count >= 2{
                    displayValue = operandStack.removeLast() * operandStack.removeLast()
                    enter()
                }
            
//            case "÷":
//            case "+":
//            case "−":
        default: break
        }
    }
```
これで✖️が実装できましたね。８　Enter　9 ✖️　で、演算ができるので確かめてみてください

```
operandStack = [8.0, 9.0]
operandStack = [72.0]
```


これを四則演算全て実装するのはかなり冗長なので、以下のように書き換えました。

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            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
    }
```

performOperationメソッドの引数が、メソッドになっていますね。
これも8 Enter 95 ✖️で演算できるので試してください

```
operandStack = [8.0, 95.0]
operandStack = [760.0]
```

ただ、これもdivideとかaddとかの演算のメソッドを加えていくのはかなり冗長なので、これも工夫していく必要があります。
ここでクロージャーを使います。

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
        case "×":performOperation({(op1,op2) in return op1 * op2})
            
//            case "÷":
//            case "+":
//            case "−":

        default: break
        }
    }
```
このようにしても動きますね。

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
        case "×":performOperation({(op1,op2) in op1 * op2})
            
//            case "÷":
//            case "+":
//            case "−":

        default: break
        }
    }
```
このようにreturnを削除しても動きます

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
        case "×":performOperation({ $0 * $1})
            
//            case "÷":
//            case "+":
//            case "−":

        default: break
        }
    }
```
$1 * $2にしても動きます。

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
        case "×":performOperation(){ $0 * $1}
            
//            case "÷":
//            case "+":
//            case "−":

        default: break
        }
    }
```
関数部を外に出しても動きますね

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
        case "×":performOperation{ $0 * $1}
            
//            case "÷":
//            case "+":
//            case "−":

        default: break
        }
    }
```
()のかっこもいらないですね。

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
        case "×":performOperation{ $0 * $1}
        case "÷":performOperation{ $1  / $0}
        case "+":performOperation{ $0 + $1}
        case "−":performOperation{ $1 - $0}

        default: break
        }
    }
```
全ての演算に関して実装しました。"÷","−"については順序が逆になるんですね。

現時点での全体的なコードは以下のようになります

```
import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var display: UILabel!
    
    var userIsInTheMiddleOfTypingANumber: Bool = false
 
    @IBAction func appendDigit(sender: UIButton) {
        let digit = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber{
            display.text = display.text! + digit
        }else{
            display.text = digit
            userIsInTheMiddleOfTypingANumber = true
        }
        
        println("digit = \(digit)")
    }
    
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            enter()
        }
        switch operation {
        case "×":performOperation{ $0 * $1}
        case "÷":performOperation{ $1  / $0}
        case "+":performOperation{ $0 + $1}
        case "−":performOperation{ $1 - $0}

        default: break
        }
    }
    func performOperation(operation: (Double,Double) -> Double){
        if operandStack.count >= 2{
            displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
            enter()
        }
    }
    
    var operandStack:Array<Double> = Array<Double>()
    @IBAction func enter() {
        userIsInTheMiddleOfTypingANumber = false
        operandStack.append(self.displayValue)
        println("operandStack = \(operandStack)")
    }
    
    var displayValue: Double {
        get{
            return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
        }
        set{
            display.text = "\(newValue)"
            userIsInTheMiddleOfTypingANumber = false
        }
    }
}
```

では、次にルートの記号を加えてみます

```
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            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
        }
    }
```
エラー出ますね。performOperationの引数が二つあるのに、使っている値が一つしかないからです。
なので、performOperation関数をコピーして以下のような関数をオーバーロードします。

```
    func performOperation(operation: Double -> Double){
        if operandStack.count >= 1{
            displayValue = operation(operandStack.removeLast())
            enter()
        }
    }
```

```
 Method 'performOperation' with Objective-C selector 'performOperation:' conflicts with previous declaration with the same Objective-C selector
```

上のようなエラーが出るので、片方または両方にprivateをつける。

```
    private 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()
        }
    }
```
完成ですね。ちゃんと動くと思います。

![Kobito.vQp9HA.png](https://qiita-image-store.s3.amazonaws.com/0/53172/aad0f4e3-0689-4b46-81ee-95650041ffef.png "Kobito.vQp9HA.png")

Costraintsを設定してやって,UpdateFrameをかけてやれば、ちゃんとUIいっぱいに設定されます。

最終的にできたコードは以下のようになります

```
import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var display: UILabel!
    
    var userIsInTheMiddleOfTypingANumber: Bool = false
 
    @IBAction func appendDigit(sender: UIButton) {
        let digit = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber{
            display.text = display.text! + digit
        }else{
            display.text = digit
            userIsInTheMiddleOfTypingANumber = true
        }
        
        println("digit = \(digit)")
    }
    
    @IBAction func operate(sender: UIButton) {
        let operation = sender.currentTitle!
        if userIsInTheMiddleOfTypingANumber {
            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
        }
    }
    private 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()
        }
    }
    
    var operandStack:Array<Double> = Array<Double>()
    @IBAction func enter() {
        userIsInTheMiddleOfTypingANumber = false
        operandStack.append(self.displayValue)
        println("operandStack = \(operandStack)")
    }
    
    var displayValue: Double {
        get{
            return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
        }
        set{
            display.text = "\(newValue)"
            userIsInTheMiddleOfTypingANumber = false
        }
    }
}
```