【iOS】iOSアプリ開発入門~ SwiftとUIの接続編3~


前回はボタンタップイベントを受けラベルの色を変更する方法について投稿しました。
SwiftとUIの接続編2:https://qiita.com/euJcIKfcqwnzDui/items/93f010b989a4d333f0b9

今回はいくつか簡単な処理を紹介します。
Swiftのコーディング練習がてらこのあたりの処理を入れてもう少しアプリらしくしてみましょう。

処理をいれる前にこちらに目を通しておくと理解しやすいかもしれません。
【付録】Swift基礎(変数・型):https://qiita.com/euJcIKfcqwnzDui/items/5d4c674a975c90a3db3f

それではいつも通りプロジェクトを開いて実装していきましょう。

カウントアップさせる処理

ボタンをタップする毎に表示される数字が増えるような処理を紹介します。

デバッグコンソールにカウントアップを表示する

まずカウントアップさせるには今いくつまでカウントされているかという状態を保持しておく必要があります。
この状態を保持するためのスペースをプロパティに準備しておきます。
以下のようにコードを編集します。

ViewController.swift
class ViewController: UIViewController {
    var count: Int = 0  // < 追加
    @IBOutlet weak var label: UILabel!

    @IBAction func tapButton(_ sender: Any) {
        self.label.text = "Hello World"
        self.label.backgroundColor = UIColor.red
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}

countというプロパティをInt型で定義しました。
Intは整数型と呼ばれるものです。数字、特に整数で扱うものはInt型で定義します。

一部例外はありますがプログラムでは型を意識する必要があります。
整数ならInt型、少数ならDouble型、文字列ならString型というようにそれぞれ用途に合わせて型を指定してあげなければいけません。
今回の場合はボタンをタップする毎に数字を1ずつ増やすという処理をしたいのでInt型として定義しました。

var count: Int = 0というように定義していますが、この= 0いうのは初期化処理です。
つまりcountの初期値は0という値ですよとしてあげています。

それではこのcountを使って実装していきます。

tapButtonの処理を以下のように書換えてみます。
書換えたら実行してボタンを何度かタップしてみてください。

ViewController.swift
    @IBAction func tapButton(_ sender: Any) {
        print("加算前:\(self.count)")
        self.count = self.count + 1
        print("加算後:\(self.count)")
        print("-----")
    }

デバッグコンソールに以下のように出力されました。
print()関数に関しては以前しました。デバッグコンソールに出力するための処理です。

加算前:0
加算後:1
-----
加算前:1
加算後:2
-----
加算前:2
加算後:3
-----

見ればなんとなくわかるかもしれませんが、ボタンをタップする度にself.count = self.count + 1という処理でcountの値に1を加算しています。

ここで出てきた=や+は演算子またはオペレータと呼ばれます。
プログラミングではこの演算子を使い計算をしていきます。
※演算子の詳細はこちらにまとめているので目を一度目を通してもらえればと思います。

「+」はそのままの意味で足し算を行います。
少し注意が必要なのは「=」で、こちらは代入演算子と呼ばれています。
数学上の意味では「=」は等価、つまり左辺と右辺の関係式を表しますがプログラム上では代入を意味します。
少しニュアンスが難しいかも知れませんがここの処理はself.count + 1の計算結果をself.countに代入しています。その結果self.countの値が1加算されたものに書き換わります。
(ちなみに等価の演算子は「==」です)

一回目のタップでは代入される前のself.countの初期値は0のためprint("加算前:\(self.count)")では「0」が表示され、加算後self.countの値は1に書き換わったためprint("加算後:\(self.count)")では「1」が表示されています。

二回目のタップではself.countの値は一回目に1に書換えているためprint("加算前:\(self.count)")では「1」が表示され、さらに書き換えを行い2に更新しています。

試しに代入を行わず以下のような処理にしてみましょう。

ViewController.swift
    @IBAction func tapButton(_ sender: Any) {
        print("加算前:\(self.count)")
        print("加算後:\(self.count + 1)")
        print("-----")
    }

以下のように出力されました。

加算前:0
加算後:1
-----
加算前:0
加算後:1
-----
加算前:0
加算後:1
-----

これはself.countに代入を行っていないため初期値の0のままになっているためです。
self.count + 1の計算はprint("加算後:\(self.count + 1)")で1と表示されているので正しく行われていますが、self.countが更新されないため同じ結果が常に表示されています。
値を更新したい場合は必ず代入するようにしてください。

このようにして値を更新、保持しながらアプリの状態を制御していきます。

カウントアップ結果をラベルに表示する

print()関数だけではアプリの表示は変更されないのでself.countを表示してみましょう。
これまでの内容を理解できていれば特に難しいことはなく、ラベルの表示変更とカウントアップの処理を組み合わせるだけです。

コードを以下の様に書き換え実行してみましょう。

ViewController.swift
    @IBAction func tapButton(_ sender: Any) {
        self.count = self.count + 1
        self.label.text = "カウント:\(self.count)"
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.label.text = "カウント:\(self.count)"
    }

ラベルの表示が「カウント:0」から始まり、ボタンをタップする毎にカウントが増えていきました。
基本的には前項の処理とは変わらずself.count = self.count + 1で1ずつ加算していき、その値をラベルに表示しているだけです。

処理をもう少し詳しく見ててみましょう。

まずtapButton内の処理について。
先程と同様にself.count = self.count + 1self.countが更新されていますね。
更新した結果をself.label.text = "カウント:\(self.count)"に代入しています。
そのためラベルには加算された値が表示されています。
ラベルの更新の際self.count\()で囲まれています。
冒頭で言いましたがプログラムでは型を意識する必要があります。
UILabelのtextの定義を見てみます。(見方は前回説明しました)

open var text: String?というように定義されています。
「?」はひとまず気にせず、String型つまり文字列型で定義されており、countInt型なので型が異なるということがわかります。
プログラムでは型が異なる場合は直接代入できないという決まりがあります。
そこでIntStringに変換してあげる必要があります。
型を変換する処理のことをキャストと呼び、\()IntStringにキャストするための処理です。
キャストしてあげた結果"カウント:\(self.count)"String型に変換されtextに代入できるようになりました。

次はviewDidLoadの処理について。
tapButtonの処理では更新した値を表示していますが、1を加算した値を表示しているため初期値の0が表示されることはありません。
そもそもtapButtonはボタンをタップするというイベントを起こして初めて動く処理のため、画面を表示した瞬間のラベルの表示を制御できません。
ですがアプリを実行したときは「カウント:0」と表示されていました。
これを実現するための処理がviewDidLoadの内容です。
このviewDidLoadはプロジェクトを作成した段階ですでに定義されていましたが、何をするための処理なんでしょう?
今回は詳しく説明しませんがアプリの画面、つまりViewControllerにはライフサイクルというものがあり、「画面が表示された」、「画面が非表示」になったなど、画面の表示状態などによって勝手に呼ばれるメソッドが元々定義されています。
viewDidLoadもライフサイクルの1つで「画面がメモリ上に確保された」タイミングで呼ばれます。
基本的にこのタイミングで画面の初期化処理を行います。
初期化処理としてself.label.text = "カウント:\(self.count)"を行ったため画面が表示された瞬間「カウント:0」と表示されていたというわけです。

カウント毎にテキストの色を変える

もう少し遊んでみましょう。
先程等価式は「==」の演算子を使うと少し話しましたがこの等価演算子を使ってみます。

プログラムには条件判定を行うためにif文を呼ばれるものが用意されています。EXCELなどにもありますがそれと同じです。
「if文」を使えば特定の条件の場合のみ行う処理を記述することができます。
(if文についてはこちらで紹介しています)

コードを以下の様に書き換え実行してみましょう。

ViewController.swift
    @IBAction func tapButton(_ sender: Any) {
        self.count = self.count + 1
        self.label.text = "カウント:\(self.count)"

        let remainder: Int = self.count % 2
        if remainder == 0 {
            self.label.textColor = UIColor.red
        } else {
            self.label.textColor = UIColor.blue
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.label.textColor = UIColor.red
        self.label.text = "カウント:\(self.count)"
    }

タップする度に文字色が赤→青→...と変わります。

viewDidLoadで文字色の初期値を赤に指定していますね。
tapButtonに注目してください。
let remainder = self.count % 2とあります。
まず「%」は余りを求める演算子です。self.count % 2self.countを2で割った余りを結果として返します。
つまり偶数の場合は0、奇数の場合は1となり、remainderには0 ro 1が代入されます。

remainder == 0ではremainderと0が等価かどうかを計算しています。
このように「==」など左右の値の関係を比較する演算子を比較演算子と呼びます。
比較演算子は他に「>」,「>=」,「<」,「<=」があります。これらの意味は数学と同じで大なり、大なりイコールといった意味になります。
比較演算子の計算結果はInt型ではなくBool型となります。Bool型は論理型と呼ばれ真偽値、つまりtrue/falseを格納します。
今回の場合0と比較しているのでremainderが0ならtrue、1ならfalseの値が返されます。
試しにprint(remainder == 0)とするとtrue or falseが表示されます。

「if文」では真偽値を判定します。
構文としては以下の様になります。

if 真偽値 {
    trueの場合の処理
} else {
    falseの場合の処理
}

従ってcountが偶数の場合は文字色が赤となり、奇数の場合は文字色が青となったというわけです。

余談ですがif文は以下のような感じでelseなしやさらにif文で繋げることもできます。

// else なし
if self.count % 2 == 0 {
    // countが「2n」の場合の処理
}

// if文を繋げる
if self.count % 3 == 0 {
    // countが「3n」の場合の処理
} else if self.count % 3 == 1 {
    // countが「3n+1」の場合の処理
} else {
    // 上記判定に当てはまらなかった場合の処理
}

最後に

今回はカウントアップや条件分岐など少しプログラミング的な処理を入れてUIを更新してみました。
もちろんこれは簡単な例でさらに複雑な処理を与えてあげればもっと細かい制御ができるようになります。

今回紹介した内容は簡単ではありますが全てのプログラミングに共通する考え方で非常に重要な内容です。
もし理解できなかった場合は読み直しさらに練習するなどで自分のものにしてください。

特にif文は非常に重要で、他に繰り返しを制御するfor文というものがありますが
if文とfor文があれば全ての処理を記述できると言われています。
しっかりと理解できるようにしましょう。

次回はアプリの画面遷移について説明していきます。
画面遷移編1:https://qiita.com/euJcIKfcqwnzDui/items/679b1cd30694519f4916

本連載ではプログラミング未経験からiOSアプリ開発が行えるようになることを目的としています。
今までの投稿をまとめていますのでこちらもご覧ください。
http://naoyalog.com/