[iOSアプリ開発] 電卓アプリ:タプル・計算プロパティ

電卓アプリを作成してみませんか?

普段何気なく使用している一般的な電卓。どのようにプログラムされているのかご存知ですか?

すなわち、数値、-などのキーを押し、最後に=キーを押した時に、どのように計算し、結果を表示しているのか。

この記事はこれらの内容について、順序立てて解説していきます。

目次

概要

この講座で学習する内容
  • 電卓アプリ作成

アプリを作成する過程で、以下の内容を学習できます。

  • 計算プロパティの使用
  • privateなどのアクセスレベルの使用
  • 構造体のプロパティの変更→mutating
  • タプルの使用
  • 以下の記事で、電卓のオートレイアウトを解説しています。

MVCデザインパターンを適用しています。
Model(M)、View(V)、Controller(C
記事中、M、V、Cの略を使用しています。

参考にした講座】iOS & Swift – The Complete iOS App Development Bootcamp (Udemy)
 (Section22) Advanced Swift Classroom – Part 2

この講座で作成するアプリの概要
  • 一般的な電卓を作成します。
  • 例えば、「1+2=3」を計算する場合は、「1」「+」が押された時点で、その情報をタプルを使用して一時的に保管します。
  • 次に「2」「=」が押された時に、一時的に保管したタプル(「1」「+」)を呼び出して、計算(「1」「+」「2」「=」)し、答えの「3」をディスプレイに表示します。
アプリの開発環境(2023年7月2日現在)
  • Xcode: Version 14.3.1
  • macOS: Venture: Version 13.4.1
  • iOS: 16.5.1
Xcodeのインストールが未了の方はこちら
GitHubからプロジェクトを入手したい方はこちら

UIの設定

開始プロジェクトをクローンして起動した状態を確認してみましょう。

開始プロジェクトの確認

開始プロジェクトの確認
  1. 表示ラベル(黄色枠)がリンクされています。
  2. 計算ボタン(+,-など、緑色枠)がリンクされています。
  3. 数値ボタン(赤色枠)がリンクされています。

ボタンの設定1

数値ボタンをディスプレイに表示する

数値ボタンをディスプレイに表示するコードを追記します。数字キーを連続して押した場合に、数字が並んで表示されるようにしています。(例)「9」「6」「5」と連続して押した場合→「965」と表示

displayLabel.text = displayLabel.text! + numValue
  1. この部分のコードは、numButtonPressed関数内のelse節に含まれています。
  2. このelse節は、isFinishedTypingNumbertrueでない場合に実行されます。
    つまり、ユーザーが既に数字の入力を開始している状態です。
  3. displayLabel.text!は、現在表示されているテキストを示しています。
    numValueは、押された数字ボタンのタイトル(文字列)を表しています。
  4. このコードの目的は、ユーザーが既に入力した数字の末尾に新しい数字を追加することです
  5. 例えば、ユーザーが最初に「9」という数字を入力した後、さらに数字「6」のボタンを押すと、このelse節が実行されます。
    その結果、displayLabel.textは「9」+「6」→「96」となり、新しい数字が既存の数字に追加されます。

計算ボタン(+/-, AC, %)の設定

計算ボタンの内、「+/-」, 「AC」, 「%」)が機能するようにコードを追記します。

if let calcMethod = sender.currentTitle

ボタンのタイトルがcalcMethodという定数に代入されます。これにより、どの計算方法が選択されたかが判断できます。

calcMethodの値に応じて、さまざまな計算方法が処理されます。以下の条件分岐が行われます:

  • +/-” と等しい場合
    displayLabel.textnumber * -1 の結果に設定されます。
    これは、表示されている数値の符号を反転させる効果があります。
  • AC” と等しい場合
    displayLabel.textは “0” に設定されます。
    これは、表示をゼロにリセットする効果があります。
  • %” と等しい場合
    displayLabel.textnumber * 0.01 の結果に設定されます。
    これは、表示されている数値を百分率に変換する効果があります。

小数点「.」の設定

現在、小数点「.」ボタンを何回でも押すことができ、下図のように正しい数値でなくなってしまうという問題があります。この問題を解消するためにコードを追記します。

if let numValue = sender.currentTitle {
  • numValueが “.”(小数点)であるかどうかを確認しています。
  • もしnumValueが “.” の場合、現在表示されているテキスト(displayLabel.text)をDouble型に変換してcurrentDisplayValueという定数に代入します。
  • テキストが数値に変換できない場合には、エラーを発生させています。
  • その後、currentDisplayValueが整数かどうかを判定するために、isIntという定数が定義されます。
  • floor(currentDisplayValue) == currentDisplayValueを使って、現在の値が小数点以下を持たない整数であるかどうかを確認します
  • もしcurrentDisplayValueが整数でない場合、処理は中断されます(return)。つまり、既に小数点が入力されている場合には新たな小数点の入力を無視します。

このコードは、既に小数点が入力されている場合には追加の小数点の入力を無視することで、不正な数値の入力を防止しています。

コードの効率化

計算プロパティを使用したコードの効率化

これまで書いてきたコードについて、計算プロパティを使用して、コードをすっきりさせましょう。

修正前
修正後(get-set)

displayValueプロパティには、getsetの2つのブロックがあります。

  • getブロック
    displayLabel.textの値をDoubleに変換し、その結果を返します。
    もし変換に失敗した場合は、致命的なエラーが発生します。
  • setブロック
    与えられた新しい値(newValue)をStringに変換して、displayLabel.textに設定します。
    つまり、displayValueに新しい値を代入すると、それがdisplayLabelに反映されます。

displayValueプロパティを使用することで、displayLabelのテキストの取得と設定がより簡潔になり、コードの再利用性と可読性が向上します。また、setブロックでは内部の状態を適切に更新することができます。

MVCデザインパターンの導入

現在、「ViewController.swift」が大きくなってきたため、その中にある計算ロジック部分を分離していきます。すなわち、MVCデザインパターンを導入していきます。

MVCデザインパターンの導入

CalculatorLogicをクラスから構造体へ変更

CalculatorLogicをクラスから構造体へ変更します。これに伴い、以下の内容についてコードを修正しています。

struct CalculatorLogic
    • Classの中にあったinit()削除
    • var numberの型をDouble?(オプショナル)にする
      →他からの参照、書き換えを防止するため、アクセスレベルをprivateにする。
      →func calculateの中にif let n = number(オプショナルバインディング)を追加
    • var numberの値を置き換える関数mutating func setNumberを作成
class ViewController
    1. private var calclator = CalculatorLogic()を@IBActionの外に出す。
    2. CalculatorLogic()()の中の引数をなくす。
      ()の中のdisplayValue読み込み前にprivate var calclator = CalculatorLogic()が読み込まれるため、displayValueがnilでも対応できるようにする。
      struct CalculatorLogicのvar numberの型をDouble?(オプショナル)にする
    3. @IBAction func calcButtonPressed(内に、calclator.setNumber(displayValue)を追記

電卓アプリの完成

現時点において、以下のようなことをできるようになりました。

  • 押した数値を表示
  • 計算キー「AC,%など」が押されるまで、数値は連続表示できる
  • 小数点が複数表示されない
  • ACを押すと0、%を押すと1/100、+/-を押すと符号反転表示

今度は、例えば、1+2=3を計算できるようにするため、以下のようなコードを追記していきます。

  1. 最初の「数値(例は1)」、「計算機ー(例は+)」を格納するタプルを作成
  2. 次の「数値(例は2)」、「=」を押したときに、計算結果(例は3)を返してくれる関数
CalculatorLogic構造体のプロパティ
  • number:
    Double型のオプショナル変数で、計算を行うための数値を保持します。
  • intermediateCalculation:
    タプル型のオプショナル変数で、中間の計算結果を保持します。
    このタプルには、1つ目の数値(n1)と計算方法(calcMethod)が含まれます。
mutating func calculate(symbol: String) -> Double?

指定された演算子に基づいて計算を行うメソッドです。ここでは、入力された演算子に応じて異なる計算処理を行います。

以下がメソッド内の詳細な解説です:

  1. if let n = number { ... }: オプショナルバインディングを使用して、numberプロパティに値が含まれている場合に処理が実行されるようにします。
    numberに値がない場合は、nilを返して処理を終了します。
  2. switch symbol { ... }: 入力された演算子(symbol)に基づいて、異なる処理を行うためにswitch文が使用されています。

switch文の中の処理について

  1. case "=":
    performTwoNumCalculation(n2: n) メソッドを呼び出します。
    この場合、現在の数値 n を引数として渡します。
  2. default::
    演算子が上記のいずれのケースにも当てはまらない場合(「+」、「-」、「×」、「÷」)
    intermediateCalculationに途中の計算情報を格納します。
private func performTwoNumCalculation(n2: Double) -> Double?

与えられた二つの数値を指定された演算子で計算するためのメソッドです。このメソッドは、途中の計算情報を用いて、二つの数値と演算子に基づいて計算を行います。

以下がこのメソッドの解説です:

  1. if let n1 = intermediateCalculation?.n1, let operation = intermediateCalculation?.calcMethod { ... }
    intermediateCalculationから途中の計算情報を取得します。
  2. これにより、演算に使用される最初の数値 n1 と演算子 operation を取得します。

演算子 operation の値に基づいて、処理されています。

  1. case "+": 演算子が + の場合、二つの数値を足し合わせてその結果を返します。
  2. case "-": 演算子が - の場合、二つの数値を引いてその結果を返します。
  3. case "×": 演算子が × の場合、二つの数値を掛けてその結果を返します。
  4. case "÷": 演算子が ÷ の場合、二つの数値を割ってその結果を返します。
  5. default:: 予期しない演算子が入力された場合に、エラーメッセージを表示してプログラムを停止させます。
  6. return nil: intermediateCalculationから取得した情報が不足している場合、または予期せぬ演算子が入力された場合、計算が行えないため、nilを返します。

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次