ドル・円換算アプリ

講義の目標

  • 変数(小数・真偽値)の概念を理解すること
  • キーボードによるテキスト入力の手法を理解すること
  • 小数の計算手法や扱い方について理解すること
  • デバッグの概念を理解すること

はじめに

このセクションでは小数の扱い方、小数同士の計算について議論していきます。さらに、キーボードによるテキスト入力等も扱います。

今回の課題アプリは「ドル円換算機」です。ある金額(ドル、または円)を入力すると、指定した変換レートに応じてもう一方の通貨に変換されるものです。

完成品のサンプルは以下よりダウンロードできます。イメージが湧かない方は是非ご確認ください。

それでは、早速開発を始めて行きましょう!

プロジェクトの立ち上げと設定

新しいアプリを作る際は、まず、新規プロジェクトを立ち上げとアプリの設定を行います。

新規プロジェクトの立ち上げ

新規プロジェクトを立ち上げます。その際、使用するテンプレートは「Single View App」となります。

入力項目名 入力値
Product Name DollarYen
Team None
Oganization Identifier 任意(自分が所属している組織の名前を入れる)
Interface Storyboard
Life Cycle UIKit App Delegete
Language Swift
Use Core Data チェックを外す
include Tests チェックを外す

アプリの設定

新規プロジェクトを立ち上げたら、アプリの設定を行います。ここで、アプリのアイコンやアプリの表示タイトル(Bundle Name)、サポートするデバイスの向き(Device Orientation)を以下のように、設定します。

その前に、今回使用する外部素材ファイルを一気にインポートしてしまいましょう。

素材ダウンロード

今回使用する素材は以下の通りです。

ファイル名 説明
icon-20pt@2x.png Notification用x2画像
icon-20pt@3x.png Notification用x3画像
icon-60pt@2x.png アイコン用x2画像
icon-60pt@3x.png アイコン用x3画像
icon-29pt@2x.png 設定用x2画像
icon-29pt@3x.png 設定用x3画像
icon-40pt@2x.png Spotlight用x2画像
icon-40pt@3x.png Spotlight用x3画像
icon-1024pt@1x.png AppStore用アイコン画像

アイコン設定

画像素材のiconフォルダの中のアイコン画像をプロジェクトに取り込んでください。

サポートするデバイスの向きの設定

サポートするデバイスの向きは、以下の通り設定します。

Bundle Nameの設定

アプリの表示タイトルを決めている設定項目「Bundle Name」を変更します。
Project Editorの「info」タブをクリックして「Bundle Name」の項目を次のように変更していきます。

項目名 入力値
Bundle Name ドル円換算機

画面のデザイン

アプリの設定が完了したら、画面のデザインを行なっていきます。Storyboardを開き、空白のキャンバス上にアイテムを配置していきます。

背景色の変更

まず、画面の背景色をデフォルトの白から黒へ変更します。ナビゲーターエリアからMainStoryboard.storyboardを選択し、Interface Builderを立ち上げます。一度View上をクリックした後、Attributes Inspectorを開き、Backgroundの色を「Black Color」に変更します。

ラベルの配置

今回のアプリでは、複数のラベルを設置する必要があります。まずは、通貨の単位を示すラベルを設置していきましょう。画面上部に変換前の単位のラベルを、画面下部に変換後の単位のラベルをそれぞれ配置します。これらは、変換のモード(「ドル→円」または「円→ドル」)に応じて、動的に変更されます。



次に、変換後の結果を示すラベルを画面下部に追加します。初期状態では、「0」としておきます。

その後、「変換レート:1ドル = 円」変換レートを案内するラベルを貼り付けます。このテキストはアプリ側から特に変更されることのない、静的なテキストとなります。

最後に、1ドルに対する日本円の金額を表示するラベルを配置します。

このように、アプリのコード側から動的に変更され得るラベルは、静的なテキストと独立した形で配置する必要があります。

テキスト入力フィールドの配置

ラベルの次は、テキスト入力画面を配置します。ライブラリーエリアより、Text Fieldを選択し、画面上部に配置します。

Segmented Controlの配置

最後に、通貨換算の手法(「ドル→円」または「円→ドル」)を選択するためのSegmented Controlという入力オブジェクトを配置します。Text Fieldと同様、ライブラリーエリアからSegmented Controlを選び、画面中央部に配置します。配置後、2つある選択肢のラベルをそれぞれ、「円→ドル」と「ドル→円」に書き換えます。

Segmented Controlは、複数の選択肢の中から1つのオブションをユーザーに選ばせる時に使われます。本講義では2つですが、3つ以上の選択肢(セグメント)必要とする場合、インスペクターからSegmentの個数を指定することが可能です。

Auto Layoutによるレイアウト設定

下記のとおりに設定してください。また、設定毎にIssuesメニューにてUpdate Frameをして設定を反映してください。

テキストフィールドのPin設定

ラベル(テキストフィールド横)のPin設定

テキストフィールド、ラベル(テキストフィールド横)のUpdate Flames

セグメントコントロールのAlign設定

セグメントコントロールのPin設定

セグメントコントロールのUpdate Flames

ラベル(換算レート)のPin設定

ラベル(換算レート金額)のPin設定

ラベル(換算レート金額)のAilgn設定

ラベル(換算レート)とラベル(換算レート金額)のUpdate Flames

ラベル(換算結果金額)のPin設定

ラベル(換算結果通貨)のPin設定

ラベル(換算結果金額)とラベル(換算結果通貨)のUpdate Flames

Auto Layoutの設定は以上です。下図のようにプレビューで表示されているか確認してください。

UIオブジェクトをコードと関連づける

Main.storyboardで配置したオブジェクトをViewController.swiftに関連付けをしましょう。下図のとおりに関連付けをしてください。

関連付けが完了すると下記のようにプログラムが追加されます。

ViewController.swift

class ViewController: UIViewController {

//金額を入力するInputField用の変数
@IBOutlet weak var inputField: UITextField!

//入力単位(円 or ドル)を表示するLabel用の変数
@IBOutlet weak var inputCurrency: UILabel!

// 通貨レートを表示するLabel用の変数
@IBOutlet weak var rateLabel: UILabel!

//「ドル→円」or「円→ドル」を選ぶためのSegmented Control用の変数
@IBOutlet weak var selector: UISegmentedControl!

// 換算後の通貨の単位(円 or ドル)を表示するLabel用の変数
@IBOutlet weak var resultCurrency: UILabel!

// 換算後の金額を表示するLabel用の変数
@IBOutlet weak var resultLabel: UILabel!

各種変数の宣言

このセクションでは、宣言すべき変数を宣言するとともに、それについての解説を行なっていきます。

前回までと同様、変数の定義はViewController.swiftの中で行います。状況に応じて、例外はあるのですが、基本的には「クラスのメンバ変数」として、必要な変数を定義していきます。その手法を以下に示します。

class クラス名(ViewControllerなど): 親クラス名 {
var xxxx = xxxx
【以下、メンバ変数一覧】
}

小数を扱う変数

前回でも少し解説しましたが、アプリ上で小数を扱うためには、小数(浮動小数点数)を扱うことのできる変数を準備する必要があります。その浮動小数点数を扱うことのできるは、主にFloat型とDouble型の変数となります。これら2つの違いを以下に示します。

データ型 データの種類 大きさ 表現できる値の範囲
float 小数 4 Byte およそ10-38~1038(有効数字7桁)
double 小数 8 Byte およそ10-308~10308(有効数字15桁)

Float型もDouble型も小数を扱えるという点では共通しているのですが、大きな違いはその大きさにあります。特に断りが無い限り、Float型は4バイト(32ビット)であるのに対して、Double型は8バイト(64ビット)となります。この違いは表現できる値の範囲に大きく影響します。例えば、Float型は小数点以下38桁までしか表現できません。対して、Double型は小数点以下308桁まで表現できます。

一般的に考えた場合、この違いはあまりに天文学的でイメージが湧きづらいかもしれませんが、例えば、細かい解析処理や割り切れない計算を行う際、Double型の方がより正確に値を把握し、扱えるということになります。一方で、Double型の変数はより多くのメモリー領域を専有してしまうという欠点があります。

メモリーの容量が極端に少ない場合は、変数を宣言する上で、必要となるメモリー領域を考慮する必要があるでしょう。一方で、iOSデバイスが持つメモリー容量は一般的なモバイルデバイスの中でも特に大きく、一部の例外を除き、Float型やDouble型のレベルではメモリーサイズを気にかける必要はあまりありません。特殊な条件や制約が無い限り、基本的にはDouble型を使用します。
今回、小数を扱えるようにすべきポイントは主に、3つあります。それらを以下に示します。

  • 金額の入力値(米ドルでは1ドル未満のセントも扱うため)
  • 通貨変換レート(1米ドルに対する日本円の金額)
  • 変換後の金額(米ドルでは1ドル未満のセントも扱うため)

これらの要素をコード上でDouble型の変数として扱うものとします。

// 入力金額を扱う変数
var input:Double = 0.0
// 換算後の金額を扱う変数
var result:Double = 0.0
// 変換レートを扱う変数
var rate:Double = 0.0

UIオブジェクトに関するインスタンス

ドル円換算機では、UILabelをはじめ、様々なUIオブジェクトを活用しています。先ほど接続したUI部品について説明します。

まず、UILabelに関しては以下の4つを宣言しています。

次に、今回新たに登場するText FieldやSegmented Controlを管理するためのインスタンスも使用しています。それらを以下に示します。

  • UISegmentedControl型…Segmented Controlを管理
  • UITextField型…Text Fieldを管理

ここで、UIオブジェクトを管理するインスタンスは全て、Storyboard上のオブジェクトと関連付ける必要があるため、「IBOutlet」を冒頭に記述する必要があります。

コードにおける変数の宣言

ここまでの解説をもとに、まずは自分でコード上の正しい場所で、メンバ変数を宣言してみてください。

※ IBOutlet接続したインスタンスについても下記のようにコメントを入れておきましょう。

ViewController.swift

class ViewController: UIViewController {

// ▼▼ 追加 ▼▼
// 入力金額を扱う変数
var input:Double = 0.0
// 換算後の金額を扱う変数
var result:Double = 0.0
// 変換レートを扱う変数
var rate:Double = 0.0
// ▲▲ 追加 ▲▲

// 入力値の通貨の単位を表示するラベル(円 or ドル)
@IBOutlet weak var inputCurrency: UILabel!
// 金額を入力するテキストフィールドのインスタンス
@IBOutlet weak var inputField: UITextField!
// 「ドル→円」or「円→ドル」を選ぶためのSegmented Controlのインスタンス
@IBOutlet weak var selector: UISegmentedControl!
// 通貨レートを表示するラベル
@IBOutlet weak var rateLabel: UILabel!
// 換算後の通貨の単位を表示するラベル(円 or ドル)
@IBOutlet weak var resultCurrency: UILabel!
// 換算後の金額を表示するラベル
@IBOutlet weak var resultLabel: UILabel!

処理の実装

変数の宣言が完了したあとは、実際の処理を実装していきます。

初期処理

カウンター同様、今回も起動時に初期化すべき変数や、行うべき処理がいくつか存在します。それらのうち、これまでの学習内容で記述できるものを以下に示します。

  • 通貨レートを120.0円とする(固定)
  • 入力値(input)を「0」とする
  • 出力結果(result)を「0」とする

まずは、自分の力で正しいと思われる場所に上記を行うコードを記述してみましょう。

編集すべきファイルは引き続きViewController.swiftであり、正しくできた場合は、以下のようになるはずです。

ViewController.swift

    override func viewDidLoad() {
super.viewDidLoad()
// ▼▼ 追加 ▼▼
// 変換レートを設定(例:1ドルあたり80.5円)
rate = 120.0
// inputとresultを0に初期化
input = 0
result = 0
// ▲▲ 追加 ▲▲
}

次に、今回新しく学ぶ初期化手法について解説します。その前に、その内容を以下に示します。

  • UI画面上に変換レート(1ドルあたり80.5円)を表示する
  • 初期状態では「円をドルに変換」するものとする
  • 小数点の桁指定

これらをコードとして表現すると、以下のようになります。

// rateLabelの値をrateの値に応じて更新(小数点以下1桁まで)
rateLabel.text = String(format: "%.1f", rate)
// 初期状態の計算方法は「円→ドル」に設定
isYenToDollar = true

UILabelにDouble型の値を表示させる時にもし少数の桁を指定したい場合、String(format:"%.1f", 変数)とすると桁を指定してDouble型を文字列に変換できます。そして、UILabeltextプロパティに代入することで、画面上のUILabelの表示内容を更新します。Double型の値を文字列に変換する際の細かい留意事項は後ほど詳しく説明します。

Bool型の変数に値を代入する際は、true(真)、またはfalse(偽)を代入式の右辺とします。これらを先ほどのoverride func viewDidLoad()メソッドに追加すると、以下のようになります。

ViewController.swift

override func viewDidLoad() {
super.viewDidLoad()
// 変換レートを設定(例:1ドルあたり80.5円)
rate = 120.0
// inputとresultを0に初期化
input = 0
result = 0
// ▼▼ 追加 ▼▼
// rateLabelの値をrateの値に応じて更新(小数点以下1桁まで)
rateLabel.text = String(format: "%.1f", rate)
// 初期状態の計算方法は「円→ドル」に設定
isYenToDollar = true
// ▲▲ 追加 ▲▲
}

この段階でRunしてみましょう。rateLabelの箇所が120.0円になっているか確認してみてください。

やるべき初期化処理は、実はもう1つあるのですが、それは後ほど、テキスト入力に関する解説を行う際に、詳しく説明します。

String型のformatについて

先ほどプログラムした下記の部分について解説します。

rateLabel.text = String(format: "%.1f", rate)

この部分はrateの変数の中に入っているDouble型(少数)のデータを文字列に変換する場合にどういった形式(フォーマット)で変換するかを指定していて%.1fと指定しています。
%.1fというのは「rageの少数のデータを小数点第1位までの形式で」という意味になり、画面に表示される内容が小数点第1位までとなります。

このように下記のルールで指定する事により様々なフォーメット形式で文字列に変換させる事が可能です。

String(format: "フォーマット形式",指定したフォーマットで文字列に変換したい変数)

フォーマット指示子の種類として下記があります。

指示子 説明
%@ 文字
%c 一つの文字
%d Integer(符号付10進数表示)
%f doubleを指数なし表示
%.1f doubleを小数点第1位まで表示
%.2f doubleを小数点第2位まで表示
%s 文字列を最初のNULLまで表示

例)

var year = 2015 // 年
var month = 8 // 月
var day = 26 // 日
print(String(format: "%d年%d月%d日",year,month,day)) // 2015年8月26日

例2)

var temp = 36.123456789
print(String(format: "%.3f",temp)) // 36.123

通貨の変換処理と小数の計算

一通り初期化の実装が完了したところで、通貨の変換処理を行うメソッドの実装をやっていきます。まずは「ViewController.swift」に以下のメソッド(処理)を記述します。

ViewController.swift

// ▼▼ 追加 ▼▼
//換算処理
func convert(){

if selector.selectedSegmentIndex == 0 {

// 円→ドル変換の場合

//ドルの金額 = 円の入力値を変換レートで割った値
result = input / rate;
// 小数点以下2桁までのみをresultLabelに表示
resultLabel.text = String(format: "%.2f", result)

}else{

// ドル→円変換の場合

// 円の金額 = ドルの入力値を変換レートで掛けた値
result = input * rate;
// 小数点以下を切り捨て、整数部分のみをresultLabelに表示
resultLabel.text = String(format: "%.0f", result)

}

}
// ▲▲ 追加 ▲▲

bool型の変数を用いた比較

比較や条件分岐に関しては次回以降で詳しく解説しましたが、ここではBool型の変数を用いた比較に関する確認を行います。

コードから見て取れるように、Bool型の変数に対しても通常の比較演算子を用いることができます。また、比較対象も「true(真)」と「false(偽)」であることがわかります。このようにBool型の変数が持つ真偽値を比較することで、場合分けを行うことができます。

掛け算・割り算と小数の扱い

プログラムの中で、掛け算を行う場合は「*(アスタリスク)」マークを、割り算を行う場合は「/(スラッシュ)」マークを演算子として用います。

// ドルの金額 = 円の入力値を変換レートで割った値
result = input / rate
// 円の金額 = ドルの入力値を変換レートで掛けた値
result = input * rate

ここで注意する点があります。Swiftでは同じ変数型同士でないと計算ができません。例えばInt型とDouble型の変数の掛け算や割り算はできません。今回はDouble型同士の掛け算、割り算なので問題はありませんがInt型などとは四則演算を行うことがありますのでその際は、どちらかの型に変換してから計算を行う雨用にしてください。

割り算における「あまり」

小数を扱わない数同士の割り算の場合、割り切れない場合は「あまり」が発生してしまいます。このあまりは一見プログラミングには関係無いように思えるかもしれません。しかし、その「あまり」を検討すると便利なケースもあります。

例えば、「Int型の変数xが2の倍数であるか確かめなさい」という課題が出されたとします。その場合、どうやって確認するのが最も効果的かを考えましょう。

プログラミングを行う場合、2つの数字で割り算を行った場合の「あまり」は「%(パーセント)」マークを演算子として用いることで、求められます。

// 5 ÷ 3 = 1 あまり 2
5 % 3 = 2
// 10 ÷ 4 = 2 あまり 2
10 % 4 = 2

「int型の変数xが2の倍数」であるという事象は、「xは2で割り切れる」、すなわち「xを2で割った時のあまりは0」であるという事象と同値です。そこで、以下のif文を用いることで、「変数xが2の倍数」であるか確認できます。

このように、割り算における「あまり」を有効に活用することで、場合分けが行えるケースがあります。このようなテクニックはプログラミングを行う上でよく活用するので、ぜひ覚えてください。

if x % 2 == 0 {
【xは2の倍数である】
}

小数の文字列への変換

今回はInt型の変数をString型の文字列に変換した上で、ラベルに適用しました。ドル円換算機でも、計算結果をUI画面上のラベルに反映させる場合、Double型の変数をString型の文字列に変換する必要があります。そのコード例を以下に示します。

// 円→ドル変換の場合
resultLabel.text = String(format: "%.2f", result)

基本的には、Int型の変数を文字列に変換する場合と大差ありません。唯一違う場所はフォーマット指定子です。小数を用いる場合は「%f」というフォーマット指定子を使います。しかし、このフォーマット指定子には留意点があります。

特に断りが無い限り、「%f」単体では小数点以下6桁までを表示してしまいます。従って、上の例で「result = 12.2」であると仮定した場合、この文字列は、「12.200000」として扱われます。

これでは、金額を換算したときに、あまりにわかりづらい計算結果が表示されてしまいます。計算結果における小数点以下の数字に関しては、ドルと円の特性を踏まえ以下のようになっていることが望ましいと言えます。

  • ドル…小数点以下2桁
  • 円…小数点以下0桁(整数部のみを表示)

そこで、役に立つのが、フォーマット指定子における表示桁数の指定です。上記例を見ると、フォーマット指定子が「%.2f」となっています。これは、「小数点以下2桁までを表示」ということを明示しています。同様に「%.4f」となっている場合は小数点以下4桁までが表示され、「%.0f」となっている場合は整数部のみが表示されます。

この機能を用いることで、「円からドルに変換」する場合と「ドルから円に変換」する場合で、表示形式を切り分けことが可能となります。その例を、以下に示します。

// 円→ドル変換の場合(小数点以下2桁まで表示)
resultLabel.text = String(format: "%.2f", result)
// ドル→円変換の場合(整数部のみ表示)
resultLabel.text = String(format: "%.0f", result)

変換手法の切り替え処理

次に、変換手法の切り替えを行うメソッド(処理)を実装していきます。今回は、変換手法の切り替えを行うにあたって、UISegmentedControlを用いました。UISegmentedControlでは、選択肢のボックスが左から「0」、「1」、「2」、という順でInt型の識別番号が割り当てられます。以下の例では、「First」という選択肢が選択されています。この場合、「First」に該当する「0」という識別番号がint型の値として「selectedSegmentIndex」というプロパティー要素に代入されます。選択内容がユーザーによって変更される度に、「selectedSegmentIndex」に代入される値は変更されます。

選択内容に応じて処理を切り分ける場合、まず、該当するSegmented Controlと紐付くIBAction型のメソッドを作成する必要があります。正しく関連付けが行われた場合、ユーザーによって選択内容が変更される度にIBAction型のメソッドが呼ばれるので、そのメソッドの中で、「selectedSegmentIndex」の値を参照し、場合分けを行います。メソッドの例を以下に示します。

// Segmented Controlの選択が変更された時の処理
@IBAction func 【メソッド名】(sender: AnyObject) {
// selectedSegmentIndexの値に応じて切り分け
if sender.selectedSegmentIndex == 0 {
【Firstが選択された場合処理】
} else if sender.selectedSegmentIndex == 1 {
【Secondが選択された場合処理】
} else if sender.selectedSegmentIndex == 2 {
【Thirdが選択された場合処理】
}
}

このIBAction型のひな形に応じて、通貨の変換モード(「ドル→円」または「円→ドル」)が変わった際の処理をViewController.swiftに記述します。メソッド名「changeCalcMethod」は、具体的には、以下の設定が必要となります。

  • isYenToDollarの真偽値の切り替え(「円→ドル」の場合は「真」)
  • inputCurrencyラベルを書き換え(「円→ドル」の場合は「円」)
  • resultCurrencyラベルを書き換え(「円→ドル」の場合は「ドル」)

最後に、変換モードが変わった際、入力値に応じて計算を行い、正しい変換結果を表示する必要があります。それを実現するためには、先程の工程で実装した「func convert()」というメソッドを呼び出します。その例を以下に示します。なお、ここにある「self」とは、「同じクラス内のメソッド」を明示しています。

self.convert()

すべての必要な機能を実装した場合、コードは以下のようなものとなります。

ViewController.swift

// ▼▼ 追加 ▼▼
@IBAction func changeCalcMethod(sender: AnyObject) {
// 左側(円→ドル)が選択された場合(selectorの値が「0」のとき)
if sender.selectedSegmentIndex == 0 {
isYenToDollar = true
inputCurrency.text = "円"
resultCurrency.text = "ドル"
// 右側(ドル→円)が選択された場合(selectorの値が「1」のとき)
} else if sender.selectedSegmentIndex == 1 {
isYenToDollar = false
inputCurrency.text = "ドル"
resultCurrency.text = "円"
}
// 通貨を変換
self.convert()
}
// ▲▲ 追加 ▲▲

changeCalcMethodのコードを記述したら、IBActionの関連付けをしておきましょう。
下図のとおりMain.storyboardのセグメントコントロールとchangeCalcMethodを関連付けしてください。

関連付けできたら一度Runして実行してみましょう。
下記のようにセグメントコントロールを選択すると、ラベルは変化する事を確認してください。

キーボード入力の取り扱い

ドル円換算機では、キーボード入力よって変換する金額を入力します。そのためのText FieldをInterface Builderを用いてUI画面上に配置したかと思いますが、それを正しく扱うためにはコーディングも必要となります。コーディングを何もせず、UI画面上にText Fieldの配置のみを行った場合、TextField をタッチすると、画面下部からキーボードが出現し、テキスト入力を行えるようになります。



しかし、このままでは入力された文字列を、コード側で受け取ったり、参照したりすることができません。その上、このままでは何をやってもキーボードは収納されず、「return」キーを押しても何もおきません。そこで、キーボード入力の正しい扱い方をここでは解説します。

UITextFieldについて

Text Fieldを管理するUITextFieldクラスは、テキストの入力操作は勿論、キーボードの管理や入力文字列の記録や操作等も包括的に扱っています。これにより、テキスト入力に関係する煩雑な手続きが簡略化されています。一方で、開発者の求める様々な要求に柔軟に対応させるために、一部処理を手動で実装しなくては行けません。デフォルト状態では「return」キーの反応が無かったり、キーボードを収納させたりすることができないのは、そのためです。

一部の処理を手動で実装する前に、Delegate通知に関する記述をコード上で行わなくてはなりません。Delegate通知とは、異なるクラス間でイベントの発生等を通知するということです。この場合は、UITextField上発生したイベントをView Controllerに通知する必要があります。

これらを踏まえ、文字入力操作を行う時の動作手順を以下に示します。少し複雑ですが、「理屈よりも手順から」ということを心がけて、学習しましょう。

  • UITextFieldDelegateプロトコルをView Controllerに設定
  • UITextFieldのDelegateをView Controllerに設定(Delegate通知)
  • 「return」キーによってキーボードを収納し、通貨変換の処理を行う
  • 入力された文字列をdouble型のデータに変換した上で、「input」に代入

プロトコルの設定について

前述した通り、まずはView Controllerに対して、UITextFieldDelegateクラスのプロトコルを設定する必要があります。まずは何も考えず、ViewController.swiftを以下のように改変してください。

ViewController.swift

【変更前】
class ViewController: UIViewController {
【変更後】
class ViewController: UIViewController, UITextFieldDelegate {
UITextFieldDelegateは、UITextFieldと他のクラス(今回の場合はView Controller)の橋渡し役を果たしています。UITextFieldDelegateプロトコルを設定することによって、UITextFieldからのDelegate通知があった場合の処理(メソッド)をView Controllerの中で定義し、実装することが許可されます。

Delegate通知の設定

プロトコルの設定を行ったら、実際のDelegate通知の受け渡し先を設定します。今回は、UITextFieldである「inputField」が発するDelegate通知をView Controller側で受け取る必要があります。そこで、View Controllerが最初に起動した時に呼ばれる、override func viewDidLoad()メソッド内に以下を追記します。

ViewController.swift

// 画面起動時に呼ばれる処理
override func viewDidLoad() {
super.viewDidLoad()
:
(省略)
:
// ▼▼ 追加 ▼▼
//inputFieldのDelegate通知設定
inputField.delegate = self;
// ▲▲ 追加 ▲▲
}

「return」キーが押された場合の処理

最後に、「return」キーが押された時に呼ばれる処理(メソッド)をView Controllerの中に実装します。「return」キーが押された場合、まずは入力された値を「input」という変数に代入し、キーボードを閉じた上で、実際の通貨換算を行う必要があります。

「return」キーが押されると、UITextFieldから受け手のクラス(今回はView Controller)に対して、Delegate通知がなされます。その際、受け手のクラス内の、「-(BOOL)textFieldShouldReturn」というようにメソッドが呼び出されます。このメソッドは自動的に生成されるものではなく、プロトコルの設定とDelegate通知の設定を行った後で、ViewController.swiftに手動で実装しなくてはいけません。以下に、実際のコードを記述します。

ViewController.swift

// ▼▼ 追加 ▼▼
// UITextFieldのキーボード上の「Return」ボタンが押された時に呼ばれる処理
func textFieldShouldReturn(_ textField: UITextField) -> Bool {

//ユーザから入力された値を変数inputへ格納する
input = atof(textField.text)

//キーボードを閉じる
textField.resignFirstResponder()

//変換処理の呼び出し
self.convert()

//メソッドを終了する
return true

}
// ▲▲ 追加 ▲▲

func textFieldShouldReturn(textField: UITextField) -> Boolが呼び出された際、引数(ひきすう)として、TextFieldが渡されます。この引数に関しては次回以降で詳しく述べますが、今は「メソッドに渡される素材」として考えてください。場合によっては、同じ画面上に複数のText Viewを配置することもあるでしょう。一方、それぞれで「return」キーが押されても、その時に発せられるDelegate通知は同一のものです。

そこで、「どのText Viewで『return』キーが押されたか」を判断するために、引数として該当するTextFieldが渡されます。このメソッドでは、そのTextFieldを「textField」という変数名を用いて参照することができます。例えば、「inputText」で「return」キーが押された場合、「textField」は「inputText」を指し示すことになります。

文字列からDouble型への変換

基本的にTextFieldに入力されたテキストはString型の文字列として取り扱われます。テキストこれまでは、Int型やDouble型の変数をString型に変換する手法は取り上げましたが、計算を正しく行うためには、ユーザーによって入力された金額(String型)をDouble型に変換する必要があります。基本的には、atofというメソッドを使うことで、容易に変換を行うことができます。その例を以下に示します。

// 受け取った入力値(String型の文字列)をDoubleに変換し、inputに代入
input = atof(textField.text)

※atofメソッドは引数のString型の文字列が変換不能文字の場合は0を返します。

ビルドとデバッグ、動作試験

これにて、すべての作業は完了となります。編集内容を全て保存し、ビルドを行なってください。このテキストの内容をすべて正しくやった場合、特に問題なくアプリが動作するはずです。しかし、人間は様々な「ミス」を犯してしまうため、その「ミス」に起因するエラーや誤動作が引き起こされる場合があります。ここでは、そのミスを発見し、取り除く作業(デバッグ)に関する解説と、「ドル円換算機」の動作試験を行います。

エラーとデバッグ

人間が犯してしまうミスで、よくあるのが、タイプミスです。ViewController.swiftを例に考えてみましょう。まず、以下のコードを見てください。

// 通貨換算における計算処理
func convert() {
// 円→ドル変換の場合
if isYenToDollar == true {
// ドルの金額 = 円の入力値を変換レートで割った値
result = input / rate
// 小数点以下2桁までのみをresultLabelに表示
resultLabel.text = String(format: "%.2f", result)
// ドル→円変換の場合
} else if isYenToDollar = false {
// 円の金額 = ドルの入力値を変換レートで掛けた値
result = input * rate
// 小数点以下を切り捨て、整数部分のみをresultLabelに表示
resultLabel.text = String(format: "%.0f", result
}
}

このコードには2つの誤りがあります。それ故、このコードを含むアプリをビルドしようとしても、エラーが発生してしまい、ビルドが一切許されないという状況に陥ってしまいます。

まずは、自分でどこにミスがあるか、じっくり考えてみてください。ここでミスを発見できれば、かなり洞察力があると言えるでしょう。しかし、プログラミングを始めたばかりの場合、慣れるまでは少し時間がかかるでしょう。幸い、Xcodeはビルド時に遭遇したエラー箇所を的確に表示してくれる機能をもっています。その例を以下に示します。

このように、Xcodeはビルド時のエラーを引き起こしている行を的確にマークしてくれます。それらを頼りに、誤りの内容を探ってみましょう。

無効な比較演算子の利用

1つ目の問題箇所は、「if文の中で比較演算子ではなく、代入演算子がつかわれているけど、大丈夫?」という内容です。

括弧の過不足

2つ目の問題箇所は、「括弧の過不足」に由来するエラーです。

このような括弧の過不足は、典型なミスの一種です。コードを記述する際は、「開いた括弧は必ず閉じる」ということは必ず肝に命じて下さい。

ビルド中にエラーやワーニングが出てしまったら、その内容に従って、コード中の問題箇所を適宜デバッグ(修正)しましょう。

動作試験

エラーやワーニングを解消できたら、実際にビルドして実行しましょう。金額を入力し、変換レートに応じて、正しく金額を換算できたら、動作試験成功となります。

まとめ

今回は、少数や真偽値の扱い方を学習しました。また、少数を用いた掛け算や掛け算、テキストの入力やSegmented Control等の使い方もカバーしました。最後にコード上のエラーの対処法やデバッグの概念も学びました。

今回扱った内容も、プログラミングを上達させる上での基礎となるものばかりです。毎回新しい内容ばかりで、体系的に概念を理解するのは大変かもしれませんが、引き続き復習と自己アレンジを積極的に行なって、「覚える」よりも「慣れる」ことに重点をおいて、学習を進めましょう。