LoginSignup
2
2

More than 5 years have passed since last update.

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

Posted at
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にすると、エラーが治る。
これはどういうことだろうか。

ここに詳しい説明が載っている。
つまり、!を使っていた場合は「暗黙的な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)")
    }

}

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

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

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

以下のような図になる。

Kobito.Cpjurr.png

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

var operandStack:Array<Double> = Array<Double>()

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

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
        }
    }

これで✖️が実装できましたね。8 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

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
        }
    }
}
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2