第04講 手拍子
印刷を御希望の方はページ一番下の「印刷用ページ」より印刷してください。
PDFファイルとして保存したい場合も「印刷用ページ」より保存できます。
見出しに「★」マークがついた箇所は説明動画がございます。
第4講のポイント
- オブジェクト指向型プログラミングの基礎概念を理解
- クラスやインスタンス、メソッドを理解
- 繰り返し(while文・for文)の概念を理解
- 配列の概念を理解
- 音声の再生手法
はじめに
前回の「ドル円換算機」では小数の扱い方、小数同士の計算について議論していきます。さらに、キーボードによるテキスト入力等も扱いました。
第4講の課題アプリは「手拍子」となります。手拍子の回数を指定して、ボタンを押すと、指定回数分の手拍子の音が鳴るという実に単純なものです。一方で、iOSプログラミングで重要となるオブジェクトクラスやメソッド等、引き続き新しい概念に関する説明を行なっていきます。
それでは、早速開発を始めて行きましょう!
プロジェクトの立ち上げと設定
新しいアプリを作る際は、まず、新規プロジェクトを立ち上げとアプリの設定を行います。
新規プロジェクトの立ち上げ
第1講と同じ要領で、新規プロジェクトを立ち上げます。その際、使用するテンプレートは「Single View Application」となります。
Product Name |
ClapBeat |
Company Identifier |
com.rainbowapps |
Device Family |
iPhone |
Use Storyboard |
チェックを入れる |
Use Automatic Reference Counting |
チェックを入れる |
Include Unit Tests |
チェックを入れる |
アプリの設定
新規プロジェクトを立ち上げたら、アプリの設定を行います。ここで、アプリのアイコンやアプリの表示タイトル(Bundle Display Name)、サポートするデバイスの向き(Device Orientation)を以下のように、設定します。
外部素材のインポート
今回使用する外部素材ファイルを一気にインポートしてしまいましょう。
今回使用する素材は以下の通りです。
icon.png |
アイコン画像 |
clap-button.png |
ボタン用画像 |
clap.wav |
手拍子の音 |
アイコン設定とサポートするデバイスの向きの設定
素材のインポートが完了したら、Project Editorを開き、アイコンをRetina Displayと書かれたエリアの上にドラッグします。
サポートするデバイスの向きとアプリの名前は以下の通り設定します。
Bundle display nameの設定
アプリの表示タイトルを決めている設定項目「Bundle Display Name」を変更します。
Project Editorの「info」タブをクリックして「Bundle Display Name」の項目を次のように変更していきます。
画面のデザイン
アプリの設定が完了したら、画面のデザインを行なっていきます。Storyboardを開き、空白のキャンバス上にアイテムを配置していきます。
Autolayoutの無効化
画面レイアウトを3.5インチ(iPhone4S以前)と4インチ(iPhone5以降)に対応させるための設定を行います。
まずはXcode4.5からデフォルトで有効になっているAutolayoutを無効にします。
※Autolayoutはまだ不安定ですので本講座はAutolayoutを無効にして画面デザインを行っていきます。
下記のように①View Controller全体を選択し、②「File Inspector」に変更して、③「Use Autolayout」のチェックを外してください。
背景色の変更
まず、画面の背景色をデフォルトの白から黒へ変更します。ナビゲーターエリアからMainStoryboard.storyboardを選択し、Interface Builderを立ち上げます。一度View上をクリックした後、Attributes Inspectorを開き、Backgroundの色を「Black Color」に変更します。
ラベルとボタンを配置
まずは、ラベルから配置します。以下のように、画面上部に説明「手拍子の回数を選んでボタンをクリック」を記したラベルを配置してください。
この時、単一のラベル内で改行するためには、ラベルのインスペクターにある「Lines」という項目を任意の行数に設定します。
次に、再生ボタン(手拍子音を鳴らすボタン)を設置します。今まで通り、ボタンを配置し、先程インポートした「clap-button.png」に置き換えましょう。
Picker Viewの設置
今回、手拍子の回数を指定するにあたって、Picker Viewを活用します。Picker Viewはルーレット形式のUIオブジェクトで、決められた選択肢の中から、ユーザーに任意のものを選ばせることができます。今後自分のアプリを構築する際には、設定画面等の中で用いると便利でしょう。
ライブラリーエリアからPicker Viewを選択し、画面下部に配置します。
このPicker Viewの中の選択肢はコード上から操作します。Interface Builder上では「Cupertino」などが表示されていますが、それは無視して構いません。
異なる画面サイズの対応
3.5インチ及び4インチ画面にて画面のレイアウトが崩れないよう対応していきます。
まず下記画面上部のLabel要素を選択した状態で「Size Inspector」を選択しAutosizingの箇所を上の部分だけ赤色実践になるように変更します。これでLabel要素が上とセンター揃えで固定されました。
ボタン要素とPicker View要素を選択してから「Size Inspector」を選択しAutosizingの箇所を下の部分だけ赤色実践になるように変更します。これでLabel要素が画面下とセンター揃えで固定されました。
下記のような画面になっていれば画面のデザインは完了となります。
オブジェクト指向型プログラミング
今回はView Controller上にコードを記述する前に、オブジェクト指向型プログラミングの概念についての解説を行うと共に、その根幹を構成するクラスやインスタンス、メソッドについての説明を行います。最初は少々手間取るかもしれませんが、Objective-C言語の考え方を理解する上では必要不可欠なので、根気よく学習して行きましょう。
オブジェクトって何?
まず、前提を話すとObjective-Cは「オブジェクト指向型のプログラミング言語」です。簡単に言うと、このオブジェクト指向型のプログラミングとは、プログラムを構成する部品を「特定機能を備えたモノ」として捉え、それら「モノ」を組み合わせてプログラムを完成させる手法です。
例えば、「乗用車」は大まかに「エンジン」、「ボディー」、「シャーシ」の3つの部品から構成されているとします。ここで述べている「オブジェクト」は「乗用車」の「エンジン」や「ボディー」、「シャーシ」のような存在です。つまり、プログラムを構成する「部品」なのです。
わかりやすくするために、上記は非常に簡単な説明になっていますが、より詳しく調べてみたいという方は、インターネットや書籍で調べてみてください。
クラスって何?
乗用車を構成する部品には、エンジンやボディー、タイヤなど様々な種類があるように、プログラムを構成するオブジェクトにも様々な種類があります。それら部品を定義したものが「クラス」となります。いわばクラスは部品の設計書です。iOSアプリはこういった様々なクラスを利用してプログラムを動かしていきます。上図の乗用車をプログラムと仮定すると、乗用車を構成するそれぞれの部品のクラスは「エンジンの設計書」、「シャーシの設計書」「ボディーの設計書」と言えます。
同じ乗用車の部品でも、エンジンとボディーでは、それらの果たす役割や特徴は大きく異なります。同様に、プログラムを構成するオブジェクトでも、クラスによって、その役割や特徴は大きく異なります。
前回までの講義で扱ったものとしては、文字列を扱うNSStringクラス、ボタンを扱うUIButtonクラスなどがあったかと思います。NSStringクラスでは文字列を効率良く扱うための役割や機能を持っている一方、UIButtonクラスではボタンの果たすべき役割や機能が一式定義されています。
NSStringやUIButtonはiOS SDKの一部として、標準で備わっているクラスですが、アプリを構築するなかで、特定の機能を備えたオリジナルのクラス(部品)を作成したいという場合もあるでしょう。当然、iOS SDKも独自のクラスを実装することを認めています。実際、皆さんは既にオリジナルクラスを作っているのです。今まで作成したアプリのViewControllerなどはまさにオリジナルのクラスを定義しているのです。(「カウンターアプリ画面のクラス」「ドル円換算アプリの画面クラス」をオリジナルで作っているのです。)その詳細や手法について解説します。
インスタンスって何?
これまでの講義で、「インスタンス」という単語を何度か目にしたかと思いますが、インスタンスとは、クラス(設計書)から作られるオブジェクト(部品)の「実体」の事です。「インスタンス」はクラスを元に好きなだけその「実体」を作る事ができます。これだけ言われてもイメージがわきづらいかと思うので、乗用車を例に考えてみましょう。
特定の例外を除いて、エンジンは1台の車に1つしかありませんが、座席のシートは搭乗人数に応じて複数個あります。一方で、それぞれのシートは場所に応じて細かい形状が少しずつ異なることからもわかるように、互いに独立したモノとなっています。このように、1つの乗用車の中で、同じ種類の部品を独立した形で複数個使用することはよくあります。その場合は下記図のようにその部品のクラスから用途にあわせて「インスタンス」を作り出す事ができます。
これは、実際のプログラムにおいても同じ事が言えます。例えば、第2講で取り上げた「カウンターアプリ」は3つのボタンがありました。これらは、押された時の処理は違うものの、「ボタン」としては双方ともUIButtonクラスのオブジェクトでした。即ち、これら2つのボタンは双方ともUIButtonクラスの「インスタンス」と言えます。
このように、インスタンスとは特定のクラスの性質を持つ、1つオブジェクト(部品)そのものなのです。同じクラスのオブジェクトでも、インスタンスは「モノ」として互いに完全に独立しているので、それぞれ別々の設定や処理を施せるのです。
メンバー変数とメソッドって何?
ここまでで、クラスとインスタンスの概念について、説明してきました。クラスは部品の種類、インスタンスは独立した部品そのもの、ということを理解できたでしょうか?
次は、それぞれのクラスの中で定義されるメンバー変数とメソッドについて議論します。メンバー変数は、クラス内で定義されたそれぞれの変数を示しています。一方で、メソッドは、各クラス内で定義された処理を示しています。
以下に、メンバー変数やメソッドの記述手法の例を示します。なお、これらはMyClassという独自クラスの一部であるとします。
// メンバー変数の宣言
@implementation MyClass {
int number1;
int number2;
int result;
}
// メソッドの記述
- (int)add:(int)a with:(int)b {
int addResult = a + b;
return addResult;
}
|
まず、3つのメンバー変数である「number1」、「number2」、「result」は「@implementation MyClass{}」の「{}」(括弧)の中に記述します。行末の「;」(セミコロン)をわすれないようにしましょう。これらメンバー変数は、クラス全体から参照することができます。
次に、MyClassの中に定義されている、「- (int)add」というメソッドに着目します。
これはみてとれるように、足し算を行うメソッドです。これは、引数(ひきすう)と返り値がある、典型的なメソッドです。引数とは、メソッドを呼び出して処理を行う際に、オプションとして渡す値です。返り値はメソッドを実行した結果、出力される1つの結果となります。
まず、引数に関してですが、1つのメソッドにつき、いくつでも設定できます。ただし、1つ目はメソッド名の直後に記述し、2つ目以降はわかりやすくするために、「ラベル」をつけます。この際、メソッド名やラベルの後に、「:」(コロン)をつけるのを忘れないように注意しましょう。引数の型に関してですが、該当する引数のデータ型を示しています。今回の例では、int型の整数となっています。
次に、メソッドの内部で宣言されている「addResult」というint型の変数ですが、これはメンバー変数ではなく、ローカル変数となります。つまり、この「addResult」はこのメソッドの内部のみで参照可能となっています。他のメソッドから参照することはできません。他のメソッドやInterface Builderから参照する必要のある変数は、すべてメンバー変数として定義する必要があります。
メソッドの型についてですが、これは返り値の型を示すものとなっています。今回はint型同士の足し算なので、その結果も当然int型の整数となります。即ち、メソッドの型もint型となります。返り値として返す値は「return」に続けて記述します。今回は単一の変数になっていますが、値としては計算結果や、メソッドの呼び出し結果も設定可能です。返り値を設定しない場合は、メソッドの型として「void」を指定します。
最後にメソッドのタイプとありますが、このメソッドは「インスタンスメソッド」と呼ばれるタイプのものです。インスタンスメソッドは、最初が「-」(マイナス)マークで始まります。通常、独自に記述するメソッドのほとんどは、インスタンスメソッドとなります。稀に、クラスの初期化処理など、特殊な処理を記述する場合は「クラスメソッド」というタイプの指定が必要なことがあります。これは「+」(プラス)マークで始まります。今後、テキスト中でクラスメソッドを利用する場合は、適宜指摘するので、安心してください。
メソッドに関する解説がひと通り、終わったところで、このメソッドの呼び出し手法を解説します。例として、同じMyClassの中の別のメソッドで、「- (int)add」を呼び出すものとします。
// number1とnumber2に値を代入
number1 = 3;
number2 = 6;
// resultに「-(int)add」の返り値を代入メソッドの記述
result = [self add:number1 with:number2];
|
まず、「number1」と「number2」にそれぞれ任意の値を代入します。その後、「[self add:number1 with:number2];」という記述によって「- (int)add」を呼び出します。「self」は同じクラス内のメソッドであるということを示しています。別のクラスから呼び出す場合は、MyClassのインスタンスを作成した上で、「self」を該当するインスタンス名に置き換えます。(呼び出すメソッドがクラスメソッドの場合は、クラス名に置き換えます。)
このように、メソッドを呼び出す場合は「[]」(括弧)で囲んで、インスタンス名とメソッド名、引数(必要な場合)を指定するのです。ここで、着目すべきところは「- (int)add」は返り値としてint型の変数を返すので、そのままresultに代入できるところです。戻り値がないメソッド(void型のメソッド)の場合は特定の変数に代入することはできません。
ここでは具体的な例を示しながら、メンバー変数やメソッド、またそれらの詳細について解説しました。次は、具体的に「手拍子」のコードを記述していきながら、実際にクラスやインスタンス、メソッド等を見ていきましょう。
独自のClapクラスの実装
ここまでで、オブジェクト指向型のプログラミングの概要を説明しましたが、大まかな流れはつかめたでしょうか。概念をひと通り解説したところで、実際にクラスを実装していきたいと思います。
今回のアプリでは、手拍子(Clap)クラスを作成します。このClapクラスは音の再生やタイミング、繰り返し処理などをすべて包括的に担うことになります。詳しい説明は作業を進めながら適宜行うので、まずは下記手順に従って、Clapクラスのひな形を作成していきましょう。
Xcode上で新規クラスの作成
まずは、Xcode上で新規クラスを作成します。ナビゲーターエリアの中にある、「ClapBeat」と書かれたフォルダを右クリックし、「New File…」メニューをクリックします。
そうすると、新規ファイル作成のダイアログが表示されるので、「Objective-C class」を選択し、「Next」をクリックします。
その後、クラス名と保存場所を聞かれます。クラス名として「Clap」を入力し、プロジェクトフォルダ内(ViewController.mなどと同じ場所)に保存するようにしてください。
クラスの新規作成が完了すると、ナビゲーターエリアの一欄に今回作成したクラスのインターフェースファイル(Clap.h)と実装ファイル(Clap.m)が表示されます。
インターフェースファイルと実装ファイルに関しては第1講で少しだけ述べましたが、これらはペアとなって始めて1つのクラスとして成立します。基本的には、実装ファイルに、メンバー変数の宣言やメソッドの記述を行い、インターフェースファイルに、外部クラスから参照され得るメソッドやメンバー変数の一覧を記述します。
Clap.mを開き、冒頭にClap.hと関連付ける以下のような記述が予めなされていることを確認して下さい。
Clap.m
System Sound Servicesを用いた音の再生
今回はSystem Sound Servicesを用いて音を再生します。この、System Sound Servicesは30秒以下の音(対応ファイル形式:CAF・MP3・WAV・AIFFなど)を再生するにあたって利用できる手法です。これを利用するにあたっては、まずは、「AudioToolbox.framework」というフレームワークをプロジェクトに取り込む必要があります。
フレームワークとは、iOSデバイス上の様々な機能やセンサーを利用する際に、コーディングが手軽になるようにiOS SDKが提供するツール群です。今回用いるAudioToolbox.frameworkは音の再生を包括的に担当するフレームワークです。
まずは、Project Editorから「Build Phases」を選び、「Link Binaries With Libraries」を開きます。その中の「+」ボタンをクリックします。
その後、追加するフレームワークを選択する画面が表示されるので、先ほどのAudioToolbox.frameworkを選びます。
正常にフレームワークがプロジェクトに追加された場合、以下のように一覧に表示されるので、確認してください。
最後に、フレームワークを用いるクラスのインターフェースファイルに、その旨を記述します。今回はClap.hを開き、以下の1行を追記します。
Clap.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
|
実装ファイルの記述
フレームワークの追加が完了したら、実装ファイルに処理を記述して行きます。「Clap.m」を開き、以下の手順に従ってください。
メンバー変数の定義
まず、以下のようにメンバー変数を定義します。
ここにある、「soundURL」はサウンドファイルの場所を示すCFURLRef形式の文字列を格納するための変数です。「soundID」はiOSが再生する音を識別するための識別子となる、SystemSoundID型のデータです。
Clap.m
@implementation Clap {
//音のファイルの所在を示すURL
CFURLRef soundURL;
//サウンドIDを生成
SystemSoundID soundID;
}
|
音の指定と再生
メンバー変数の宣言が終わったら、音ファイルの指定と音の再生に関わるメソッドをClap.mに記述します。
Clap.m
//音ファイルを読み込んで設定
-(void)setSound {
//ファイルを読み込んで、soundURLを生成
CFBundleRef mainBundle = CFBundleGetMainBundle();
soundURL = CFBundleCopyResourceURL(mainBundle, CFSTR("clap"),CFSTR("wav"), nil);
//soundURLをもとに、soundIDを生成
AudioServicesCreateSystemSoundID(soundURL, &soundID);
}
//soundIDを再生
-(void)play {
AudioServicesPlaySystemSound(soundID);
}
|
今回は、再生する音の指定を行う「-(void)setSound」メソッドと、実際に音の再生を行う「-(void)play」メソッドの2つを分けて実装します。System Sound Servicesを用いる場合、まずはプロジェクトに取り込んだファイル名をもとに、soundURLを生成します。今回は、「clap.wav」というwav形式のファイルを参照しています。その後soundURLをもとに、識別子であるsoundIDを生成します。音を再生する場合はsoundIDを指定して再生します。
なお、これら2つのメソッドの型は「void」となっています。このように返り値のないメソッドは、return文が無いことに注目してください。
while文を用いたループ
今回、ユーザーによって指定された回数分、手拍子が繰り返し再生される仕組みとなっています。その際、ループ(繰り返し処理)を用いると便利です。
代表的なループの一種として、while文が挙げられます。Clap.mの中に、新たに「-(void)repeatClap:(int)count」というメソッドを作成し、その中にwhile文によるループを実装していきます。
while文では、繰り返し条件が真である限り、無限に内部の処理が繰り返されます。その構文例を以下に示します。
Clap.m
//while文による繰り返し
-(void)repeatClap:(int)count {
//iの値を初期化
int i = 0;
//while文を使って、countの回数分だけ繰り返し
while(i < count) {
//音を再生
[self play];
//iの値を1つ増やす
i++;
//0.5秒(500000マイクロ秒)静止
usleep(500000);
}
}
|
「-(void)repeatWhile:(int)count」のメソッドの中では、まず、ローカル変数として「i」が宣言されており、初期状態では、「i = 0」となっています。このメソッドでは、int型の引数として「count」があります。メソッドが呼ばれる際、この「count」には指定された手拍子の回数が入ります。
while文では条件文として「i < count」が指定されています。ループが1サイクル終わるに度に、「i」の値と「count」の値が比較され、「真」となれば処理は続けられ、「偽」となれば打ち切られます。実際のループ中では、先ほど記述した自クラス(Clapクラス)内の「-(void)play」メソッドが呼ばれ、手拍子音が1度鳴り、「i」が1つずつ増加します。手拍子音の再生の間隔を調整するために、処理を指定ミリ秒の間、一時停止するための「usleep()」が呼ばれます。なお、自クラスのメソッドを呼び出す際、インスタンス名として「self」が指定されていることを確認してください。
ループ(繰り返し)という概念はプログラミングにおいて、非常によく用いられます。大切な概念なので、よく覚えるようにしてください。
初期化処理
ここまでの手順で音の指定や再生、ループを行うメソッドを実装しました。次は、Clapクラスのインスタンスが生成された際、まず呼ばれる初期化処理を実装していきます。引き続き、Clap.mに以下のメソッドを追加します。
Clap.m
//初期化処理
+ (id)initClap {
return [[self alloc] init];
}
- (id)init {
self = [super init];
[self setSound];
return self;
}
|
他のクラスでClapクラスのインスタンスを生成する場合、インスタンスを宣言した後、まず「+(id)initClap」メソッドを呼び、初期化処理を施す必要があります。初期化処理が順当に行われない場合、様々なエラーや誤動作を引き起こす原因となるので、注意が必要です。
この初期化処理では、インスタンスが生成された際のメモリー確保と音の設定が行われます。着目すべきは、「+(id)initClap」メソッドが「+」(プラス)マークで始まっている点です。これは、クラスメソッドと呼ばれ、初期化処理などの特別な場合に用いられるものです。
ここまでで、実装ファイルへの記述はすべて完了となります。
インターフェースファイルにおけるプロトタイプ宣言
実装ファイル(Clap.m)への記述が全て終わったら、最後にインターフェースファイルにプロトタイプ宣言を行います。プロトタイプ宣言とは、メソッドの一覧を、予め宣言しておく作業を示します。他クラス、自クラス問わず、実装したメソッドを呼び出すためには必須の作業となっています。
以下の例に従って、Clap.mで実装したメソッドをClap.h上でプロトタイプとして宣言します。
Clap.h
@interface Clap : NSObject
//各種メソッドの定義
+(id)initClap;
-(void)repeatClap:(int)count;
@end
|
見て取れる通り、メソッドのプロトタイプを宣言する場合、記述すべき内容は、以下の2となっています。
- メソッドのタイプ(インスタンスメソッド/クラスメソッド)
- メソッドの型
- メソッドの名前
- 引数の型(すべての引数について)
- 引数の名前(すべての引数について)
このようなプロトタイプ宣言を行なって、初めてメソッドを呼び出す準備は整います。プロトタイプ宣言を正しく行っていない状況下で、メソッドを呼びだそうとすると、以下のようなエラーが発生し、コンパイルが完了しません。今後もしこのようなエラーを目にした場合、メソッドのプロトタイプ宣言を確認しましょう。
プロトタイプ宣言をもって、Clapクラスの実装はすべて完了となります。次は、このClapクラスのインスタンスをView Controllerで生成し、手拍子音が指定回数分だけ鳴るようにします。
View Controllerの実装
もう気づいた方もいらっしゃるかもしれませんが、これまでコードを記述してきたView Controllerもクラスの1つです。View Controllerは、画面上UIオブジェクト(ボタンやラベルなど)と内部のインスタンスやメソッドを結びつけ、ユーザーの操作によって様々な処理が行われるようするためのものです。
iOSアプリにおいて、1つの画面につき、View Controllerクラスが1つずつ必要となっています。複数の画面を擁するアプリは次回の第5講で取り扱いますが、今回は引き続き画面が単一のアプリとなるので、今まで同様、予め用意されたView Controllerを編集していきます。
Clapクラスの利用準備
最初に、View Control内でClapクラスを利用する旨を記す必要があります。ViewController.hの冒頭に以下の1行を追記して下さい。
ViewController.h
#import <UIKit/UIKit.h>
#import "Clap.h"
|
前回までと同様、以下の例に従ってメンバー変数の宣言を行います。
ViewController.m
@implementation ViewController{
Clap *clapInstance;
IBOutlet UIPickerView *PickerView;
NSString *repeatNumbersForPicker [10];
int repeatCount;
}
|
ここで宣言されている「clapInstace」は、先程実装したClapクラスのインスタンスです。「pickerView」はPicker Viewを掌るUIPickerViewのインスタンスです。この中に「NSString *repeatNumbersForPicker [10]」という、見慣れない形式のメンバー変数が1つあるかと思います。これは、NSString型のインスタンスの「配列」を示しているもので、Picker Viewの選択肢の一覧を格納します(配列に関しては、後ほど詳しく説明していきます)。「repeatCount」は、実際にユーザーによって選ばれた手拍子の数を格納します。
View Controllerの初期処理と配列
前回までと同様、画面が最初に立ち上がり時に呼ばれる「- (void)viewDidLoad」というメソッドを以下のように改変します。
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
//clapを初期化
clapInstance = [Clap initClap];
//初期の手拍子の数として1(1回)を指定
repeatCount = 1;
//Picker Viewの選択肢一覧を準備
for (int i = 0; i < 10; i++) {
NSString *numberText = [NSString stringWithFormat:@"%d回", i+1];
repeatNumbersForPicker[i] = numberText;
}
}
|
見慣れない構文もあるかと思いますが、順次解説するので安心して下さい。
clapインスタンスの初期化
先ほどの、Clapクラスを実装する過程で、インスタンスが生成された際の初期化処理を記述したかと思います。今回、新たにClapクラスのインスタンスである、「clapInstance」を生成しました。そこで、View Controllerの初期処理の一部に、「clapInstance」の初期化を盛り込みましょう。
//clapを初期化
clapInstance = [Clap initClap];
|
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人の学生のテストの点数を管理する場合の変数を考えてみましょう。
配列を宣言する際、配列の大きさ(格納するデータの個数)を指定する必要があります。上の例では、int型の整数を10個分確保した配列、「score」を宣言しています。
ここで、重要なことは、一つ目の要素は「0番目」という要素番号を与えられることです。つまり、配列の大きさを10とした場合、要素番号は「0」から「9」までとなります。各要素は、単独の変数と同じように扱えます。例えば、「score」の5番目の要素に「43」という数字を代入する場合、以下のように記述します。
さらに、配列の要素を参照する場合、変数を用いて要素番号を指定することも出来ます。以下にその例を示します。
for (int i = 0; i < 10; i++) {
score[i] = (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型の小数はもちろんの事、NSStringやUIButtonなどを含む、各種クラスのインスタンスも配列として扱うことができます。適宜、状況に応じて配列を有効に活用すると、非常に効率の良いコーディングができます。
Picker View向けの選択肢文字列の準備
今回、View Controllerの初期処理の一部で、Picker View向けの選択肢文字列の準備を行なっている部分があります。「手拍子」で設置するPicker Viewは、手拍子の回数を指定するためのものです。
今回は「1回」から「10回」までの10個の選択肢を準備します。差し当たり、ルーレットの中に登場する10個分の選択肢の文字列を予め設定しておく必要があるのです。
それら文字列を格納するのが、「repeatNumbersForPicker」というNSString型の文字列の配列です。先ほど記述したコードにある通り、for文によるループを用いて、「repeatNumbersForPicker」の各要素に「1回」から「10回」までの文字列を代入しています。
//Picker Viewの選択肢一覧を準備
for (int i = 0; i < 10; i++) {
NSString *numberText = [NSString stringWithFormat:@"%d回", i+1];
repeatNumbersForPicker[i] = numberText;
}
|
Picker Viewを利用する準備
第3講で扱ったキーボード入力同様、Picker Viewの利用に関しても、少々特殊な準備が必要となります。ViewController.hを開き、以下のようにプロトコルを設定します。
ViewController.h
@interface ViewController : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate>
|
Picker Viewの選択肢の設定
プロトコルの設定を行ったら、Picker Viewのルーレットに表示される選択肢を設定します。ViewController.mを開き、3つのメソッドを記述する必要があります。
まずは、Picker Viewの列の数を設定するメソッドです。列の数とは、Picker Viewで選択するデータの種類の数です。今回は手拍子の回数の1つなので、以下のように記述します。
ViewController.m
//PickerViewの列の数を指定
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
//今回は1つのカラム(手拍子の回数)のみ
return 1;
}
|
次に、列の要素数を設定するメソッドです。今回は、「1回」から「10回」まで10個の選択肢(要素)を準備するので、以下のように記述します。
ViewController.m
//カラムの要素数を指定
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
//今回は10個の要素(「1回」~「10回」)
return 10;
}
|
最後に、PickerView各要素の表示文字列を指定します。初期処理の段階で、各選択肢(要素)の文字列を格納した「repeatNumbersForPicker」という配列に、適宜文字列を代入したかと思います。ここに格納されている値をPicker Viewの各要素の文字列として設定するので、以下のよう記述します。
ViewController.m
//選択肢要素の表示文字列
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
//row番目の要素に表示する文字列
return repeatNumbersForPicker[row];
}
|
このメソッドは、Picker Viewの要素数分だけ呼び出されます。その都度、「row」という引数に、「0」から「9」まで要素番号が渡されます。この引数を用いて、「repeatNumbersForPicker」の値を参照し、Picker Viewの各要素に文字列を設定します。
Picker Viewの選択内容を反映
Picker Viewの選択肢の設定が終わったところで、その選択内容が変更された場合の処理を実装していきます。ユーザーがルーレットを操作し、Picker Viewの値を変更した場合に呼ばれるメソッドを、以下のようにViewController.mに設定します。
ViewController.m
//選択肢が変更された際の処理
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
//繰り返し回数は(row+1)回
//例:4番目の要素 =>「5回」=> 繰り返し回数は(4+1=5)回
repeatCount = row+1;
}
|
Picker Viewの選択内容が変更された際、選択された要素の要素番号が「row」という引数を用いて渡されます。例えば「5回」が選択された場合、「row」には「4」が渡されます。よって、手拍子の回数が変更された場合、新たな回数である、「row + 1」を「repeatCount」に代入します。
再生ボタンが押された際の処理
Picker Viewに関わるすべての実装が終わった所で、最後に再生ボタン(手拍子ボタン)が押された際の処理を実装します。以下のようにViewController.mにIBAction型のメソッドを定義します。
ViewController.m
//再生ボタンが押された際の処理
- (IBAction)play:(id)sender {
//Clapクラスの中のメソッドを呼び出し、指定回数分再生
[clapInstance repeatClap:repeatCount];
}
|
ここで着目すべきは、Clapクラスのインスタンスである、「clapInstance」を用いて、Clapクラスの「-(void)repeatClap:(int)count」というメソッドを呼び出している点です。この際、「count」という引数に、「repeatCount」を渡しています。これにより、指定された回数分だけ、手拍子音が再生されます。
これにて、View Controller上の実装はすべて完了となります。この後、メソッドやインスタンスをStoryboard上のUIオブジェクトと関連づけて、「手拍子」の完成となります。
UI画面とコードの関連付け
ここまでで、基本的にコードの記述は全て完了となります。そこで、これまでに設置したUI画面上の部品とコード上の処理を関連付けます。
Picker Viewの関連付け
今回は、手拍子の回数を選択するために、Picker Viewを設置しました。下記手順に従って、このPicker Viewの関連付けを行います。
まずは、Picker Viewを右クリックし、インスペクターを開きます。「Outlets」以下にある、「dataSource」と「delegate」を両方共View Controllerにアサインします。
次に、PickerView自身をView Controllerで宣言した「pickerView」インスタンスと関連付けます。やり方は、これまで扱ったラベル等と全く同じです。
これで、Picker Viewの関連付けはすべて完了です。
再生ボタンの関連付け
最後に、再生ボタンと、View Controller上の「-(IBAction)play」を関連付けます。やり方は、前回までの講義で扱った各種ボタンと全く同じです。
ビルドと動作試験
これにて、すべての作業は完了となります。編集内容を全て保存し、ビルドを行なってください。このテキストの内容をすべて正しくやった場合、特に問題なくアプリが動作するはずです。
ここで、注意すべき点が1つあります。iOSシミュレーターを用いて音の再生を試す場合、PCの環境によっては正しく再生されないというバグが、一部報告されています。そこで、音の再生の試験を行う場合、可能な限り実機を用いて行うことを強く推奨します。
アプリが正常に起動することを確認した上で、Picker Viewの選択肢が正常に設定されていることや、選択内容に応じて適切な回数の手拍子音が鳴ることを確認してください。
まとめ
第4講では、Objective-Cにおいて、基本となるクラスやインスタンス、メソッドの概念を網羅的に学習しました。同時に、while文やfor文を用いたループ(繰り返し)や配列についても学習しました。さらに、iOSアプリにおける短い音声の再生手法も扱い、アプリ上で音を再生できるようになったかと思います。
クラスやインスタンス、メソッドの考え方は少し複雑で、なかなか理解出来ない場合もあるかと思います。しかし、これら知識は今後の講義をすすめる上で必要不可欠なので、復讐を重ねて理解するようにしましょう。また、これら概念は非常に奥が深く、説明を簡略化するために、細部の解説を一部割愛している部分があります。このテキストの解説を完全に理解できた方は、Objective-Cの専門書等も読み、クラスやメソッドに関する詳細な理解を深めることが出来れば、なお良いかと思います。
最後に、余力のある方は今回の「手拍子」アプリを独自に改変し、新しい拍手音を追加したり、再生のタイミングを工夫したりしてみましょう。