サイトアイコン BergamotMagic

おそるおそるSwift 2-5 デンタッキー(電卓)を作る ~プリンタ機能を追加する~

Swift5+Xcode11.6

今回のゴール

 続きです。入力履歴機能を追加しました。コードはContentView.swiftに書きました。

https://bergamotmagic.tokyo/wp-content/uploads/2020/08/4788686c32cd8af72b5974b2bf5e4147.mp4
プレビュー

 後半は変更がないので省略しています。

import SwiftUI

struct ContentView: View {
    @State var inputArray :[String] = []    //リスト表示用
    @State var inputStr :String = ""   
    let CalStr :[String] = ["+","-"]    //計算記号一覧
    
    func outputStr(tmpStr :String) {
        //        var str1 :String = ""
        if tmpStr == "C" {
            self.inputStr = ""
            self.inputArray = []
        } else if tmpStr == "=" {
            var tmpStr2 :String = ""     //配列の文字をキャッシュ
            var tmpResult :Double = 0.0 //計算途中の数値をキャッシュ
            var symbol :String   //四則計算の区別
            
            self.inputArray.append(self.inputStr)
            self.inputStr = tmpStr
            
            for item in self.inputArray {
                let str = item
                let start1 = str.startIndex     //配列要素の最初の文字を取得
                symbol = String(str[start1])
                if self.CalStr.contains(symbol) == false {
                    tmpResult = atof(item)  //atofは文字列をDoubleに変換する関数
                    print("I'm Here!")
                } else {
                    tmpStr2 = String(str.suffix(item.count - 1))
                    print("tmpStr2\(tmpStr2)")
                    switch symbol {
                    case "+":
                        tmpResult += atof(tmpStr2)
                    case "-":
                        tmpResult -= atof(tmpStr2)
                    default:
                        tmpResult = 9999999.0
                    }
                }
            }
            self.inputStr = String(tmpResult)
        } else if (self.CalStr.contains(tmpStr))&&(inputStr != "") {
            self.inputArray.append(self.inputStr)
            self.inputStr = tmpStr
        } else {
            self.inputStr += tmpStr
        }
    }
    
    func delete(at offsets: IndexSet) {
        if let first = offsets.first {
            self.inputArray.remove(at: first)
        }
    }
    
    var body: some View {
        VStack {
            List{
                ForEach (self.inputArray, id: \.self) { index in
                    Text(index)
                }
            .onDelete(perform: delete)
            }
                   //配列データの一意性を保証するために、id: \.selfが必要。
            VStack {
                Text("\(self.inputStr)")
                    .font(.largeTitle)
                    .fontWeight(.heavy)
                    .foregroundColor(Color.red)
                    .multilineTextAlignment(.trailing)
                    .frame(width: 300.0)

 とりあえず、計算結果表示用テキストフィールドの上に、リストを追加しています。いまさらですが、VBAやその他の言語のようにオブジェクトに名前をつけて、処理対象となるオブジェクトを指定する方法ではなく、オブジェクトそのものに処理内容を入れるSwiftUIはかなり個性的で、慣れが必要です。
 ついでにForEach構文も慣れる必要があります。58~61行目は次のような記述も可能です。

            List{
                ForEach (0..<self.inputArray.count,id: \.self) { index in
                    Text(self.inputArray[index])
                }

 いずれにせよ、id:\.selfは必須で無いとエラーになります。まあ、Xcodeが直してくれますが。
 62行目の.onDeleteは、リストの項目を削除させるときの処理内容を指定するための予約語です。デンタッキーでは、func delete(50〜54行目)が実行されます。この部分はサイトで拾ってきたのでやや意味を理解しきれていないのですが、.onDeleteから対象となる場所(Indexset)を引数でもらい、それを配列番号に変換して削除しているのだろうと、今のところ理解しています。
 ちなみに、Indexsetは”1 indexes”を返し、ユーザ定義関数first(=Indexset.first)は削除対象の行列番号を返します。

次回は

 細かいイレギュラー入力への対応や加減以外の計算機能は実装していませんが、とりあえず自分なりの目標には到達したので一旦ここで開発を終了します。
 興味がある方はシリーズ3もご覧ください!

モバイルバージョンを終了