手拍子アプリ

講義の目標

  • オブジェクト指向型プログラミングの基礎概念を理解すること
  • クラスやインスタンス、メソッドを理解すること
  • 繰り返し(while文・for文)の概念を理解すること
  • 配列の概念を理解すること
  • 音声の再生手法をマスターすること

はじめに

今回の課題アプリは手拍子となります。手拍子の回数を指定して、ボタンを押すと、指定回数分の手拍子の音が鳴るという実に単純なものです。一方で、iOSプログラミングで重要となるオブジェクトクラスやメソッド等、引き続き新しい概念に関する説明を行なっていきます。

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

iOS完成品サンプル(手拍子アプリ)

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

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

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

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

Welcom to Xcode画面から、Create a new Xcode projectを選択します。そしてSingle View Appを選択します。

入力項目名 入力値
Product Name ClapBeat
Team None
Oganization Name 任意(”ALJ”など自分が所属している組織の名前を入れる)
Oganization Identifier jp.co.al-j
Language Swift
User Interface Storyboard
Use Core Data チェックを外す
include Unit Tests チェックを外す
include UI 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用アイコン画像
img_sound.pdf 効果音再生イメージ画像
btn_play.pdf 効果音再生用ボタン用画像
clap.wav 手拍子の音

AppIcon の設定

ナビゲータエリアからAssets.xcassets > AppIcon を選択し、以下のようにアイコン画像を設定します。

Device Orientation の設定

次に、対象デバイスとサポートするデバイスの向きの設定を行います。

ナビゲータエリアからproject > General を選択し、Development infoを以下の設定にします。

Development info

Target Device 入力値
iOS13.5 iPhone チェックをする
iOS13.5 iPad チェックをはずす
Device Orientation Portrait チェックをする
Device Orientation Upside Down チェックをはずす
Device Orientation Landscape Left チェックをはずす
Device Orientation Landscape Right チェックをはずす

Bundle Nameの設定

アプリの表示タイトルを決めている設定項目Bundle Nameを変更します。

infoタブを選択し、Bundle Nameを次のように変更します。

Custom iOS Target Properties

Key Type Value
Bundle Name String 手拍子

画面のデザイン

画面を作成していきます。

スプラッシュ画面の設定

スプラッシュ画面を作成します。

今回は以下のように、背景色(background)をSystem Purple Color、中央にLabelを設置し、text項目に文字列手拍子を設定します。

background の設定

ナビゲーターエリアからLaunchScreen.storyboard を選択し、ViewController > View > Attributes inspector を選択し、 BackgroundSystem Purple Color に設定します。

Labelの設置

ライブラリーエリアを選択し、 LaunchScreen.storyboard 上に Label を配置し、 Label に対して以下の設定を行います。

Labelプロパティ名 設定値
Text Hello
Color White Color
Font 50px
Alignment centor

AutLayoutの設定

Labelに対して、以下の「制約(Constraint)」を設定します。

警告が表示されている場合には以下のように対応してください。

警告が表示されていなければOKです。

メイン画面の設定

次にメイン画面の設定をおこなっていきます。

PDF画像の取り込み

メイン画面で扱う画像ファイルを取り込みます。

PDF画像は以下の①〜③の手順で取り込みます。

① ナビゲーターエリアから Assets.xcassets を選択します。

② 画像ファイルを Assets.xcassets へドラック&ドロップします。

③ Attribute Inspecterを表示させ、ScalesSingle Scaleへ設定します。

※ Xcode6からPDF形式のベクター画像をアプリで表示する事ができるようになりました。
ベクターが扱えるようになったということは、いままでのように RetinaNon Retina で別々の画像を用意する必要がなくなったり、イメージを複数のサイズの View に配置したいときに1つのファイルだけ用意すれば良くなるということです。

これで通常の画像と同じように扱えます。

imageViewの配置

メイン画面を設定します。

ナビゲーションエリアからMain.storyboardを選択します。

ライブラリーエリアから ImageView を選択して画面上部に配置してください。

次にSize Inspecterを表示させ、 WidthHeight100にして正方形の形にしてください。

Valueプロパティ名 設定値
Width 100
Height 100

Attributes inspector を選択し、Image Viewimageへ以下のように設定します。

Image Valueプロパティ名 設定値
image img_sound

次にAutolayoutの設定をします。

Image Viewに対して、以下の「制約(Constraint)」を設定してください。

Labelの配置

ライブラリーエリアを選択し、 Main.storyboard 上に Label を配置し、 Label に対して以下の設定を行います。

Labelプロパティ名 設定値
text 手拍子の回数を選んでボタンをクリック
line 2

次に、Autolayoutの設定をします。

Labelに対して、以下の「制約(Constraint)」を設定してください。

Buttonの配置

次に、再生ボタン(手拍子音を鳴らすボタン)を設置します。今まで通り、ボタンを配置し、先程インポートしたbtn_playに置き換えましょう。

Buttonプロパティ名 設定値
Type Custom
title (空白)
image btn_play

次に、Autolayoutの設定をします。

Buttonに対して、以下の「制約(Constraint)」を設定してください。

Picker Viewの設置

今回、手拍子の回数を指定するにあたって、Picker Viewを活用します。Picker Viewはルーレット形式のUIオブジェクトで、決められた選択肢の中から、ユーザーに任意のものを選ばせることができます。今後自分のアプリを構築する際には、設定画面等の中で用いると便利でしょう。

ライブラリーエリアからPicker Viewを選択し、画面下部に配置します。

このPicker Viewの中の選択肢はコード上から操作します。Interface Builder上では「Cupertino」などが表示されていますが、それは無視して構いません。

次に、Autolayoutの設定をします。

Picker Viewに対して、以下の「制約(Constraint)」を設定してください。

UIオブジェクトをコードと結びつける

ここでMain.storyboardとコードをアシスタントエディタで接続します。
下図のとおりに、Buttonには IBAction を、Picker Viewには IBOutlet の関連付けをしてください。

ViewController.swift

import UIKit

class ViewController: UIViewController {

//PickerView用の変数
@IBOutlet weak var pickerVier: UIPickerView!

override func viewDidLoad() {
super.viewDidLoad()

}

//Buttonクリックした際の処理
@IBAction func play(_ sender: Any) {
}

}

オブジェクト指向型プログラミング

今回はView Controller上にコードを記述する前に、オブジェクト指向型プログラミングの概念についての解説を行うと共に、その根幹を構成するクラスやインスタンス、メソッドについての説明を行います。最初は少々手間取るかもしれませんが、Swift言語の考え方を理解する上では必要不可欠なので、根気よく学習して行きましょう。

オブジェクトって何?

まず、前提を話すとSwiftは「オブジェクト指向型のプログラミング言語」です。簡単に言うと、このオブジェクト指向型のプログラミングとは、プログラムを構成する部品を「特定機能を備えたモノ」として捉え、それら「モノ」を組み合わせてプログラムを完成させる手法です。

例えば、「乗用車」は大まかに「エンジン」、「ボディー」、「シャーシ」の3つの部品から構成されているとします。ここで述べている「オブジェクト」は「乗用車」の「エンジン」や「ボディー」、「シャーシ」のような存在です。つまり、プログラムを構成する「部品」なのです。

わかりやすくするために、上記は非常に簡単な説明になっていますが、より詳しく調べてみたいという方は、インターネットや書籍で調べてみてください。

クラスって何?

乗用車を構成する部品には、エンジンやボディー、タイヤなど様々な種類があるように、プログラムを構成するオブジェクトにも様々な種類があります。それら部品を定義したものが「クラス」となります。いわばクラスは部品の設計書です。iOSアプリはこういった様々なクラスを利用してプログラムを動かしていきます。上図の乗用車をプログラムと仮定すると、乗用車を構成するそれぞれの部品のクラスは「エンジンの設計書」、「シャーシの設計書」「ボディーの設計書」と言えます。

同じ乗用車の部品でも、エンジンとボディーでは、それらの果たす役割や特徴は大きく異なります。同様に、プログラムを構成するオブジェクトでも、クラスによって、その役割や特徴は大きく異なります。

前回までの講義で扱ったものとしては、文字列を扱うStringクラス、ボタンを扱うUIButtonクラスなどがあったかと思います。Stringクラスでは文字列を効率良く扱うための役割や機能を持っている一方、UIButtonクラスではボタンの果たすべき役割や機能が一式定義されています。

StringやUIButtonはiOS SDKの一部として、標準で備わっているクラスですが、アプリを構築するなかで、特定の機能を備えたオリジナルのクラス(部品)を作成したいという場合もあるでしょう。当然、iOS SDKも独自のクラスを実装することを認めています。実際、皆さんは既にオリジナルクラスを作っているのです。今まで作成したアプリのViewControllerなどはまさにオリジナルのクラスを定義しているのです。(「カウンターアプリ画面のクラス」「ドル円換算アプリの画面クラス」をオリジナルで作っているのです。)その詳細や手法について解説します。

インスタンスって何?

これまでの講義で、「インスタンス」という単語を何度か目にしたかと思いますが、インスタンスとは、クラス(設計書)から作られるオブジェクト(部品)の「実体」の事です。「インスタンス」はクラスを元に好きなだけその「実体」を作る事ができます。これだけ言われてもイメージがわきづらいかと思うので、乗用車を例に考えてみましょう。

特定の例外を除いて、エンジンは1台の車に1つしかありませんが、座席のシートは搭乗人数に応じて複数個あります。一方で、それぞれのシートは場所に応じて細かい形状が少しずつ異なることからもわかるように、互いに独立したモノとなっています。このように、1つの乗用車の中で、同じ種類の部品を独立した形で複数個使用することはよくあります。その場合は下記図のようにその部品のクラスから用途にあわせて「インスタンス」を作り出す事ができます。

これは、実際のプログラムにおいても同じ事が言えます。例えば、前回の「カウンターアプリ」は3つのボタンがありました。これらは、押された時の処理は違うものの、「ボタン」としては双方ともUIButtonクラスのオブジェクトでした。即ち、これら2つのボタンは双方ともUIButtonクラスの「インスタンス」と言えます。

このように、インスタンスとは特定のクラスの性質を持つ、1つオブジェクト(部品)そのものなのです。同じクラスのオブジェクトでも、インスタンスは「モノ」として互いに完全に独立しているので、それぞれ別々の設定や処理を施せるのです。

メンバー変数とメソッドって何?

ここまでで、クラスとインスタンスの概念について、説明してきました。クラスは部品の種類、インスタンスは独立した部品そのもの、ということを理解できたでしょうか?
次は、それぞれのクラスの中で定義されるメンバー変数とメソッドについて議論します。メンバー変数は、クラス内で定義されたそれぞれの変数を示しています。一方で、メソッドは、各クラス内で定義された処理を示しています。

以下に、メンバー変数やメソッドの記述手法の例を示します。なお、これらはMyClassという独自クラスの一部であるとします。

class MyClass {

// メンバー変数の宣言
var number1 = Int()
var number2 = Int()
var result = Int()

// メソッドの記述
func add(a:Int, b:Int) -> Int {
let addResult = a + b
return addResult
}

}

まず、3つのメンバー変数である「number1」、「number2」、「result」は「class MyClass{}」の「{}」(括弧)の中に記述します。これらメンバー変数は、クラス全体から参照することができます。

次に、MyClassの中に定義されている、「func add(a: Int, b: Int) -> Int」というメソッドに着目します。

func add(a:Int, b:Int) -> Int {

let addResult = a + b
return addResult

}

これはみてとれるように、足し算を行うメソッドです。これは、引数(ひきすう)と返り値がある、典型的なメソッドです。引数とは、メソッドを呼び出して処理を行う際に、オプションとして渡す値です。返り値はメソッドを実行した結果、出力される1つの結果となります。

まず、引数に関してですが、1つのメソッドにつき、いくつでも設定できます。この際、ラベルの後に、「:」(コロン)をつけるのを忘れないように注意しましょう。引数の型に関してですが、該当する引数のデータ型を示しています。今回の例では、Int型の整数となっています。

次に、メソッドの内部で宣言されている「addResult」というInt型の変数ですが、これはメンバー変数ではなく、ローカル変数となります。つまり、この「addResult」はこのメソッドの内部のみで参照可能となっています。他のメソッドから参照することはできません。他のメソッドやInterface Builderから参照する必要のある変数は、すべてメンバー変数として定義する必要があります。

メソッドの型についてですが、これは返り値の型を示すものとなっています。今回はInt型同士の足し算なので、その結果も当然Int型の整数となります。即ち、メソッドの型もInt型となります。返り値として返す値は「return」に続けて記述します。今回は単一の変数になっていますが、値としては計算結果や、メソッドの呼び出し結果も設定可能です。

最後にメソッドのタイプとありますが、このメソッドは「インスタンスメソッド」と呼ばれるタイプのものです。インスタンスメソッドは、「func」で始まります。通常、独自に記述するメソッドのほとんどは、インスタンスメソッドとなります。稀に、クラスの初期化処理など、特殊な処理を記述する場合は「クラスメソッド」というタイプの指定が必要なことがあります。これは「class func」で始まります。今後、テキスト中でクラスメソッドを利用する場合は、適宜指摘するので、安心してください。

メソッドに関する解説がひと通り、終わったところで、このメソッドの呼び出し手法を解説します。例として、同じMyClassの中の別のメソッドで、「func add」を呼び出すものとします。

// number1とnumber2に値を代入
number1 = 3
number2 = 6
// resultに「fucn add」の返り値を代入メソッドの記述
result = self.add(number1, b: number2)

まず、「number1」と「number2」にそれぞれ任意の値を代入します。その後、「self.add(number1, b: number2)」という記述によって「func add」を呼び出します。「self」は同じクラス内のメソッドであるということを示しています。別のクラスから呼び出す場合は、MyClassのインスタンスを作成した上で、「self」を該当するインスタンス名に置き換えます。(呼び出すメソッドがクラスメソッドの場合は、クラス名に置き換えます。)

このように、メソッドを呼び出す場合は「[]」(括弧)で囲んで、インスタンス名とメソッド名、引数(必要な場合)を指定するのです。ここで、着目すべきところは「fucn add」今回は返り値としてInt型の変数を返すので、そのままresultに代入できるところです。戻り値がないメソッドの場合は特定の変数に代入することはできません。

ここでは具体的な例を示しながら、メンバー変数やメソッド、またそれらの詳細について解説しました。次は、具体的に「手拍子」のコードを記述していきながら、実際にクラスやインスタンス、メソッド等を見ていきましょう。

独自のClapクラスの実装

ここまでで、オブジェクト指向型のプログラミングの概要を説明しましたが、大まかな流れはつかめたでしょうか。概念をひと通り解説したところで、実際にクラスを実装していきたいと思います。

今回のアプリでは、手拍子(Clap)クラスを作成します。このClapクラスは音の再生やタイミング、繰り返し処理などをすべて包括的に担うことになります。詳しい説明は作業を進めながら適宜行うので、まずは下記手順に従って、Clapクラスのひな形を作成していきましょう。

Xcode上で新規クラスの作成

まずは、Xcode上で新規クラスを作成します。ナビゲーターエリアの中にある、「ClapBeat」と書かれたフォルダを右クリックし、「New File…」メニューをクリックします。

そうすると、新規ファイル作成のダイアログが表示されるので、「Cocoa Touch class」を選択し、「Next」をクリックします。

その後、クラス名と保存場所を聞かれます。クラス名として「Clap」を入力し、Subclassを「NSObject」にし、Languageを「Swift」にして、プロジェクトフォルダ内(ViewController.swiftなどと同じ場所)に保存するようにしてください。

クラスの新規作成が完了すると、ナビゲーターエリアの一欄に今回作成したクラスの「Clap.swift」が表示されます。

ClapBeatディレクトリ配下へ配置します。

これで独自のクラスの作成ができました。

System Sound Servicesを用いた音の再生

今回はSystem Sound Servicesを用いて音を再生します。この、System Sound Servicesは30秒以下の音(対応ファイル形式:CAF・MP3・WAV・AIFFなど)を再生するにあたって利用できる手法です。

AudioToolboxフレームワークの取り込み

System Sound Servicesを利用するにあたっては、まずは、「AudioToolbox.framework」というフレームワークをプロジェクトに取り込む必要があります。

フレームワークとは、iOSデバイス上の様々な機能やセンサーを利用する際に、コーディングが手軽になるようにiOS SDKが提供するツール群です。今回用いるAudioToolbox.frameworkは音の再生を包括的に担当するフレームワークです。

まずは、Project Editorから「General」を選び、「Link Frameworks and Libraries」を開きます。その中の「+」ボタンをクリックします。

その後、追加するフレームワークを選択する画面が表示されるので、先ほどのAudioToolbox.frameworkを選びます。

正常にフレームワークがプロジェクトに追加された場合、以下のように一覧に表示されるので、確認してください。

音ファイルの取り込み

音を再生させるファイルをプロジェクトに取り込んでおきます。
下図のとおりに素材フォルダからclap.wavを選択してプロジェクトのナビゲーションエリアにドラッグしてください。

ドラッグしたら下記の画面がでますので①〜②の手順でインポートしてください。

プロジェクトに取り込まれていると下記のように表示されます。

実装ファイルの記述

フレームワークを用いるクラスのインターフェースファイルに、その旨を記述します。今回はClap.swiftを開き、以下の1行を追記します。

Clap.swift

import UIKit

// ▼▼ 追加 ▼▼
import AudioToolbox
// ▲▲ 追加 ▲▲

フレームワークの追加が完了したら、実装ファイルに処理を記述して行きます。Clap.swiftを開き、以下の手順に従ってください。

メンバ変数の定義

まず、以下のようにメンバ変数を定義します。
ここにある、soundURLはサウンドファイルの場所を示すNSURL形式の文字列を格納するための変数です。soundIDはiOSが再生する音を識別するための識別子となる、SystemSoundID型のデータです。

Clap.swift

import UIKit

import AudioToolbox

class Clap: NSObject {

// ▼▼ 追加 ▼▼

//音のファイルの所在を示すURLを格納するための変数
var soundURL = NSURL()

//サウンドIDを格納するための変数
var soundID = SystemSoundID()

// ▲▲ 追加 ▲▲

}

音の指定と再生

メンバー変数の宣言が終わったら、音ファイルの指定と音の再生に関わるメソッドをClap.swiftに記述します。

Clap.swift

// ▼▼ 追加 ▼▼
func setSound() {

//ファイルを読み込んで、soundURLを生成
let mainBundle = CFBundleGetMainBundle()
soundURL = CFBundleCopyResourceURL(mainBundle, "clap" as CFString?, "wav" as CFString?, nil)

//soundURLをもとに、soundIDを生成
AudioServicesCreateSystemSoundID(soundURL, &soundID)

}

//soundIDを再生
func play() {

AudioServicesPlaySystemSound(soundID)

}
// ▲▲ 追加 ▲▲

今回は、再生する音の指定を行うfunc setSound()メソッドと、実際に音の再生を行うfunc play()メソッドの2つを分けて実装します。System Sound Servicesを用いる場合、まずはプロジェクトに取り込んだファイル名をもとに、soundURLを生成します。今回は、clap.wavというwav形式のファイルを参照しています。その後soundURLをもとに、識別子であるsoundIDを生成します。音を再生する場合はsoundIDを指定して再生します。

なお、これら2つのメソッドの型はvoidとなっています。このように返り値のないメソッドは、return文が無いことに注目してください。

while文を用いたループ

今回、ユーザーによって指定された回数分、手拍子が繰り返し再生される仕組みとなっています。その際、ループ(繰り返し処理)を用いると便利です。

代表的なループの一種として、while文が挙げられます。Clap.swiftの中に、新たにfunc repeatClap(count: Int)というメソッドを作成し、その中にwhile文によるループを実装していきます。

while文では、繰り返し条件が真である限り、無限に内部の処理が繰り返されます。その構文例を以下に示します。

Clap.swift

// ▼▼ 追加 ▼▼

//while文による繰り返し
func repeatClap(count: Int) {
var i = 0

//while文を使って、countの回数分だけ繰り返し
while(i < count) {

//音を再生
self.play()

//iの値を1つ増やす
i = i + 1

//0.5秒(500000マイクロ秒)静止
usleep(500000)

}

}

// ▲▲ 追加 ▲▲

func repeatClap(count: Int)のメソッドの中では、まず、ローカル変数として「i」が宣言されており、初期状態では、「i = 0」となっています。このメソッドでは、Int型の引数として「count」があります。メソッドが呼ばれる際、この「count」には指定された手拍子の回数が入ります。

while文では条件文として「i < count」が指定されています。ループが1サイクル終わるに度に、 i の値と count の値が比較され、「真」となれば処理は続けられ、「偽」となれば打ち切られます。実際のループ中では、先ほど記述した自クラス(Clapクラス)内のfunc playメソッドが呼ばれ、手拍子音が1度鳴り、 i が1つずつ増加します。手拍子音の再生の間隔を調整するために、処理を指定ミリ秒の間、一時停止するための usleep() が呼ばれます。なお、自クラスのメソッドを呼び出す際、インスタンス名としてselfが指定されていることを確認してください。

ループ(繰り返し)という概念はプログラミングにおいて、非常によく用いられます。大切な概念なので、よく覚えるようにしてください。

初期化処理

ここまでの手順で音の指定や再生、ループを行うメソッドを実装しました。次は、Clapクラスのインスタンスが生成された際、まず呼ばれる初期化処理を実装していきます。引き続き、Clap.swiftに以下のメソッドを追加します。

Clap.swift

//初期化処理
override init() {

super.init()

setSound()

}

initはインスタンスの初期化時に呼ばれる特殊なメソッドで、他のオブジェクト指向のプログラム言語ではコンストラクタと呼ばれているものです。initの箇所にインスタンス生成時の処理を実装します。

また、overrideとはサブクラス(ここではClapクラス)でスーパーク
ラス(ここではNSObjectクラス)のメソッドを実装しなおす場合につけます。initはNSObjectのメソッドなのでそれを実装しなおしsetSoundメソッドを追加しています。

以上でClapクラスの実装はすべて完了となります。次は、このClapクラスのインスタンスをView Controllerで生成し、手拍子音が指定回数分だけ鳴るようにします。

ViewControllerの実装

もう気づいた方もいらっしゃるかもしれませんが、これまでコードを記述してきたView Controllerもクラスの1つです。View Controllerは、画面上UIオブジェクト(ボタンやラベルなど)と内部のインスタンスやメソッドを結びつけ、ユーザーの操作によって様々な処理が行われるようするためのものです。

iOSアプリにおいて、1つの画面につき、View Controllerクラスが1つずつ必要となっています。複数の画面を擁するアプリは次回以降で取り扱いますが、今回は引き続き画面が単一のアプリとなるので、今まで同様、予め用意されたView Controllerを編集していきます。

Clapクラスの利用準備

最初に、View Control内でClapクラスを利用する旨を記す必要があります。メンバ変数を下記のように追加してください。

ViewController.swift

class ViewController: UIViewController {

@IBOutlet weak var PickerView: UIPickerView!

// ▼▼ 追加 ▼▼

//clapのインスタンスを管理する定数
let clapInstance = Clap()

// pickerViewの表示文字列を管理する変数
var repeatNumbersForPicker = NSMutableArray()

//音を鳴らす回数を管理する変数
var repeatCount = Int()

// ▲▲ 追加 ▲▲

ここで宣言されている「clapInstace」は、先程実装したClapクラスのインスタンスです。「PickerView」はPicker Viewを掌るUIPickerViewのインスタンスです。この中に「var repeatNumbersForPicker = NSMutableArray()」という、見慣れない形式のメンバー変数が1つあるかと思います。これは、NSMutableArray型のインスタンスの「配列」を示しているもので、Picker Viewの選択肢の一覧を格納します(配列に関しては、後ほど詳しく説明していきます)。「repeatCount」は、実際にユーザーによって選ばれた手拍子の数を格納します。

ViewControllerの初期処理と配列

前回までと同様、画面が最初に立ち上がり時に呼ばれる「override func viewDidLoad()」というメソッドに以下を追加します。

ViewController.swift

override func viewDidLoad() {

super.viewDidLoad()

// ▼▼ 追加 ▼▼

//初期の手拍子の数として1(1回)を指定
repeatCount = 1

//Picker Viewの選択肢一覧を準備
for i in 0 ..< 10 {

let numberText = String(format: "%d回", i+1)

// NSMutableArray版
repeatNumbersForPicker[i] = numberText

}

// ▲▲ 追加 ▲▲

}

見慣れない構文もあるかと思いますが、順次解説するので安心して下さい。

for文によるループ

Clapクラスの中で繰り返しを実現したときには、while文によるループを用いました。しかし、while文と同じレベルで頻繁に使われるループ手法として、for文があります。

for文の大きな特徴は、構文の中に「カウンター変数」というものが織り込まれていることです。while文では、単純に条件文があり、条件が「真」である限り、半永久的に処理が繰り返されます。一方、for文では条件文以外に、カウンター変数の初期値とカウンター変数の更新処理を記述する必要があります。以下にその例を示します。

まず、ループが開始する前にカウンター変数が初期値にセットされます。上の例では、Int型のカウンター変数「i」に「0」がセットされます。ループが1サイクル完了すると、カウンター変数の更新処理が呼ばれます。上の例では、「i」に「1」が足されます。カウンター変数の更新が行われたあとで、条件文が「真」となる場合は、繰り返し処理は続行されます。上の例では、「i」が「10」未満の場合のみ、繰り返し処理を行うようになっています。よって、「i」が「0」から「9」まで推移する間、即ち、10サイクル分の繰り返し処理が続行します。

for文では、カウンター変数(上の例では「i」)の値を繰り返し処理の中で参照することができます。つまり、サイクルの回数に応じて、内部処理を切り替えたりすることができます。

このfor文もwhile文同様、よく使うので、しっかり考え方を理解し、使い方を覚えるようにしましょう。

配列

配列とは、同じ種類のデータを1つのグループとして扱うテクニックです。同じ種類のデータを複数扱う必要がある場合、1つ1つ変数を宣言してもいいのですが、同じような変数名が多く存在すると、ソースコードが煩雑になってしまいます。
そこで、配列を使うことで、同じようなデータを1つのグループとして宣言し、「要素番号」という数字を用いて、それぞれの値を参照できるようになるのです。例として、10人の学生のテストの点数を管理する場合の変数を考えてみましょう。

var score: [Int] = [53, 64, 94, 76, 43, 100, 45, 65, 36, 89]

ここで、重要なことは、一つ目の要素は「0番目」という要素番号を与えられることです。つまり、配列の大きさを10とした場合、要素番号は「0」から「9」までとなります。各要素は、単独の変数と同じように扱えます。例えば、「score」の5番目の要素に「43」という数字を代入する場合、以下のように記述します。

score[5] = 43

さらに、配列の要素を参照する場合、変数を用いて要素番号を指定することも出来ます。以下にその例を示します。

for i in 0 ..< 10 {
score.append((i + 1) * 100)
}

上の例では、for文によるループによって、「i」が「0」から「9」まで推移しながら、10サイクル分の繰り返し処理が実行されます。その際、「score」の要素番号のところに「i」が指定されていることに着目してください。このように、変化する変数を用いて、その都度、値の代入先を変更することができるのです。上の例の場合は、代入する値は「(i + 1) * 100」となっています。よって、scoreの各要素には以下の値が代入されます。

要素
score[0] 100
score[1] 200
score[2] 300
score[3] 400
score[4] 500
score[5] 600
score[6] 700
score[7] 800
score[8] 900
score[9] 1000

今回は例としてInt型の整数を用いましたが、Float型やDouble型の小数はもちろんの事、StringやUIButtonなどを含む、各種クラスのインスタンスも配列として扱うことができます。適宜、状況に応じて配列を有効に活用すると、非常に効率の良いコーディングができます。

Picker View向けの選択肢文字列の準備

今回、View Controllerの初期処理の一部で、Picker View向けの選択肢文字列の準備を行なっている部分があります。「手拍子」で設置するPicker Viewは、手拍子の回数を指定するためのものです。
今回は「1回」から「10回」までの10個の選択肢を準備します。差し当たり、ルーレットの中に登場する10個分の選択肢の文字列を予め設定しておく必要があるのです。

それら文字列を格納するのが、「repeatNumbersForPicker」というNSString型の文字列の配列です。先ほど記述したコードにある通り、for文によるループを用いて、「repeatNumbersForPicker」の各要素に「1回」から「10回」までの文字列を代入しています。

//Picker Viewの選択肢一覧を準備
for i in 0 ..< 10 {

let numberText = String(format: "%d回", i+1)

// NSMutableArray版

repeatNumbersForPicker[i] = numberText

}

Picker Viewを利用する準備

Picker Viewの利用に関しては、少々特殊な準備が必要となります。ViewController.swiftを開き、以下のようにプロトコルを設定します。

ViewController.swift

変更前

class ViewController: UIViewController {

変更後

class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {

Picker Viewの選択肢の設定

プロトコルの設定を行ったら、Picker Viewのルーレットに表示される選択肢を設定します。ViewController.swiftを開き、3つのメソッドを記述する必要があります。
まずは、Picker Viewの列の数を設定するメソッドです。列の数とは、Picker Viewで選択するデータの種類の数です。今回は手拍子の回数の1つなので、以下のように記述します。

ViewController.swift

// ▼▼ 追加 ▼▼

//PickerViewの列の数を指定
func numberOfComponents(in pickerView: UIPickerView) -> Int{

//今回は1つのカラム(手拍子の回数)のみ
return 1

}

// ▲▲ 追加 ▲▲

次に、列の要素数を設定するメソッドです。今回は、「1回」から「10回」まで10個の選択肢(要素)を準備するので、以下のように記述します。

ViewController.swift

// ▼▼ 追加 ▼▼

//カラムの要素数を指定
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {

//今回は10個の要素(「1回」~「10回」)
return 10

}

// ▲▲ 追加 ▲▲

最後に、PickerView各要素の表示文字列を指定します。初期処理の段階で、各選択肢(要素)の文字列を格納した「repeatNumbersForPicker」という配列に、適宜文字列を代入したかと思います。ここに格納されている値をPicker Viewの各要素の文字列として設定するので、以下のよう記述します。

ViewController.swift

// ▼▼ 追加 ▼▼
//選択肢要素の表示文字列
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {

//row番目の要素に表示する文字列
return repeatNumbersForPicker[row] as? String

}

// ▲▲ 追加 ▲▲

このメソッドは、Picker Viewの要素数分だけ呼び出されます。その都度、「row」という引数に、「0」から「9」まで要素番号が渡されます。この引数を用いて、「repeatNumbersForPicker」の値を参照し、Picker Viewの各要素に文字列を設定します。

次に、PickerViewのDelegateとDataSourceにselfを指定します。「override func viewDidLoad()」メソッドに下記のソースを追加してください。

override func viewDidLoad() {

super.viewDidLoad()

//Picker Viewの選択肢一覧を準備
for var i = 0; i < 10; i++ {

var numberText = String(format: "%d回", i+1)

// NSMutableArray版
repeatNumbersForPicker[i] = numberText


}
// ▼▼ 追加 ▼▼

// PickerViewのDelegateをselfにする
pickerVier.delegate = self

// PickerViewのDataSourceをselfにする
pickerVier.dataSource = self

// ▲▲ 追加 ▲▲

}

PickerViewの選択内容を反映

Picker Viewの選択肢の設定が終わったところで、その選択内容が変更された場合の処理を実装していきます。ユーザーがルーレットを操作し、Picker Viewの値を変更した場合に呼ばれるメソッドを、以下のようにViewController.swiftに設定します。

ViewController.swift

// ▼▼ 追加 ▼▼
//選択肢が変更された際の処理
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

//繰り返し回数は(row+1)回
//例:4番目の要素 =>「5回」=> 繰り返し回数は(4+1=5)回
repeatCount = row+1

}
// ▲▲ 追加 ▲▲

Picker Viewの選択内容が変更された際、選択された要素の要素番号が「row」という引数を用いて渡されます。例えば「5回」が選択された場合、「row」には「4」が渡されます。よって、手拍子の回数が変更された場合、新たな回数である、「row + 1」を「repeatCount」に代入します。

再生ボタンが押された際の処理

Picker Viewに関わるすべての実装が終わった所で、最後に再生ボタン(手拍子ボタン)が押された際の処理を実装します。以下のようにViewController.swiftのIBAction型のplayのメソッドに定義します。

ViewController.swift

//再生ボタンが押された際の処理
@IBAction func play(_ sender: AnyObject) {

// ▼▼ 追加 ▼▼
//Clapクラスの中のメソッドを呼び出し、指定回数分再生
clapInstance.repeatClap(count: repeatCount)
// ▲▲ 追加 ▲▲
}

ここで着目すべきは、Clapクラスのインスタンスである、「clapInstance」を用いて、Clapクラスの「func repeatClap(count: Int)」というメソッドを呼び出している点です。この際、「count」という引数に、「repeatCount」を渡しています。これにより、指定された回数分だけ、手拍子音が再生されます。

これにて、View Controller上の実装はすべて完了となります。

ビルドと動作試験

これにて、すべての作業は完了となります。編集内容を全て保存し、ビルドを行なってください。このテキストの内容をすべて正しくやった場合、特に問題なくアプリが動作するはずです。

ここで、注意すべき点が1つあります。iOSシミュレーターを用いて音の再生を試す場合、PCの環境によっては正しく再生されないというバグが、一部報告されています。そこで、音の再生の試験を行う場合、可能な限り実機を用いて行うことを強く推奨します。

アプリが正常に起動することを確認した上で、Picker Viewの選択肢が正常に設定されていることや、選択内容に応じて適切な回数の手拍子音が鳴ることを確認してください。

まとめ

今回は、Swiftにおいて、基本となるクラスやインスタンス、メソッドの概念を網羅的に学習しました。同時に、while文やfor文を用いたループ(繰り返し)や配列についても学習しました。さらに、iOSアプリにおける短い音声の再生手法も扱い、アプリ上で音を再生できるようになったかと思います。

クラスやインスタンス、メソッドの考え方は少し複雑で、なかなか理解出来ない場合もあるかと思います。しかし、これら知識は今後の講義をすすめる上で必要不可欠なので、復讐を重ねて理解するようにしましょう。また、これら概念は非常に奥が深く、説明を簡略化するために、細部の解説を一部割愛している部分があります。このテキストの解説を完全に理解できた方は、Swiftの専門書等も読み、クラスやメソッドに関する詳細な理解を深めることが出来れば、なお良いかと思います。

最後に、余力のある方は今回の「手拍子」アプリを独自に改変し、新しい拍手音を追加したり、再生のタイミングを工夫したりしてみましょう。