i phoneアプリ入門 第4回
TRANSCRIPT
第4回 iPhone勉強会
13年3月17日日曜日
・第5回 TableView続き・第6回 ユーザ操作(タップなど)の検出方法
現在地の取得方法・第7回 MapKitを使った地図の表示方法
ブラウザでGoogleMapを表示する
今後の予定
13年3月17日日曜日
・前回の復習・protocolとdelegate・テーブルビュー・タイマー(一定時間ごとに処理を実行)・サンプルアプリ作成
今日のアジェンダ
13年3月17日日曜日
今日のスケジュールは以下の通りです。まず、前回の復習を軽く行った後、キーパッドの閉じかたとデリゲートについて勉強します。その後、テーブルビューについて勉強します。タイマーについては時間があったら行う予定です。今日も手を動かしていきましょう。よろしくおねがいします。
~以下のようなアプリを作ってみましょう~
前回の復習
押すと次の画面へ移動する
動かすと文字色が変わる
13年3月17日日曜日
まず、前回の復習をしましょう。前回受講したという前提で、まずはコードを書いてみます。図のようなアプリを作ってみましょう。iPhone上でボタンを押したら次の画面が表示される次の画面ではRGBをスライダーで設定し、設定した値が最初の画面に反映される・前回やったシングルトンを使います。何のことだかさっぱりわからないと言う方、こっそり教えてください・・・。
前回勉強したこと
• 強い参照と弱い参照→循環参照が発生するものにはweakを使う • MVCモデル→Model/View/Controllerの3つで役割分担
• シングルトン→プログラム中でオブジェクトを一つだけもつ
13年3月17日日曜日
前回学習したことを少し思い出してみましょう前回はこの3つのことについて勉強しました。・強い参照と弱い参照→Objective-Cはリファレンスカウンタ方式をとっており、オブジェクトが誰からも参照されなくなったら、メモリから解放されるのですが、オブジェクト同士が参照し合っている場合はいつまでもメモリから解放されず、メモリリークを起こしてしまいます。StoryBoardでviewに部品を配置する場合など、オブジェクト同士が参照し合う場合は弱い参照(weak)を使ってスコープ外のオブジェクトをメモリから消してしまいます。
MVCモデル→Objective-CではMVCモデルを使って、Model/View/Controllerの3つで役割分担をしています。Model:データの保持や更新を行うView:Modelの内容を表示するController:ユーザ操作を受け付けたり、Modelの操作を行う
・シングルトンJavaでもよく出てくるデザインパターンで、オブジェクトを一つだけ持つものです。どこからでもアクセスしたいオブジェクトに対して適用します。
~機能を追加しましょう~
protocolとdelegate
13年3月17日日曜日
では、ここで復習で作ったアプリに機能を1つ追加しましょう。色の変更だけでなく、表示する文字列を変更するようにしてみましょう。2番目に表示される画面で文字入力を行ってその結果を最初の画面に反映するようにしましょう。2番目の画面ではテキストフィールドというものを使いましょう。
キーパッドを閉じるには
キーパッドが閉じないのは不便・・・
13年3月17日日曜日
使ってみて、不便に思ったことは無いでしょうか。「キーパッドが閉じてくれない」「入力してもすぐに反映してくれない」この2つはキーパッドを閉じるという機能を実装していない為に発生しています。では、キーパッドを閉じるようにしましょう。
リターンキーでキーパッドを閉じる
リターンキーを押されたことを検知する
キーパッドを閉じる
UITextFieldDelegateを使って検知
13年3月17日日曜日
リターンキーを押したときにキーパッドを閉じるには図のような処理フローになります。アプリでリターンキーを押されたことを検知したらキーパッドを閉じるという処理を行うのです。リターンキーを押されたということを検知するには、UITextFieldDelegateというprotocolを使う必要があります。
protocolって
オブジェクトの役割や振る舞いを表すメソッドの集合実装は各オブジェクト内で行う →Javaでいうインターフェース
iOSのSDKに定義されているprotocolを使うことも自分で作ることも出来る。
13年3月17日日曜日
protocolというと、ネットワークの世界ではおなじみですが、Objective-Cの世界では、オブジェクトの役割や振る舞いを表すメソッドの集合のことをさします。メソッド名および引数のみヘッダファイルに設定しており、実装は各オブジェクト内で行います。
Javaでいうインターフェースと同じだと考えてください。元々はオブジェクト同士の通信規約のことでしたが、だんだん意味が広くなったようです。
iOSのSDKに定義されているプロトコルを使うことも自分でプロトコルを作ることも出来ます。
protocolの使用例
DVD Player iPod
同じメソッドでもオブジェクトによって動作を変える
再生する
13年3月17日日曜日
protocolはどのように使用するのでしょうか。ご存知の方には釈迦に説法かと思いますが念のため説明します。Javaでいうinterfaceのように同じメソッドでもオブジェクトによって処理を変えたい場合に使います。例えば同じ「再生する」という動作でもDVDプレーヤーで再生する場合とiPodで再生する場合、機械のなかで行っている処理は異なっている訳です。ただし、使う側は機械のなかで行っている処理についてはあまり気にしません。「再生する」という行為を行えば目的を達成できるのです。
protocolの使用例
オブジェクトA オブジェクトB
他のオブジェクトに通知などのメッセージを送る
「テキストの中身変わったよ」
「リターンキーおされたよ」
13年3月17日日曜日
先ほどの例を応用し、Objective-Cではこんな使い方をします。あるオブジェクトから他のオブジェクトに対して通知を行うのです。例えばオブジェクトAが「自分の持っているテキストの内容が変わった」という内容の通知を行うことが出来るのです。UITextFieldの場合、「リターンキーが押された」という通知を行うことが出来ます。
UITextFieldDelegate
UITextField.hを開いてください
テキスト
@protocolから@endまでに書かれたメソッドがプロトコルになる
プロトコルで設定しているメソッド。実際の処理は実装
側で書く
13年3月17日日曜日
プロトコルが何なのかということがわかった所で、実際に使うものを見ていきましょう。UITextField.hを開いてください。Xcodeの左側のウィンドウからFrameworksというディレクトリを開き、UIKit.frameworkを開いてください。そこにUITextField.hというヘッダがあるのでそれを開きましょう。
ファイルの下の方に@protocolUITextFieldDelegateという記載があると思います。@protocolと書くとここから@endまでの間に書いているメソッドはプロトコルだということをコンパイラに知らせています。UITextFieldの場合、テキストの編集が終わった場合の動作やリターンキーを押されたときの動作について、メソッド名だけ記載しておき、実際の処理は実装側に委譲しているのです。
~ここまでのまとめ~
•UITextFieldDelegateというprotocolを使う
•リターンキーが押されるとtextFieldShouldReturnが呼ばれる
•textFieldShouldReturnの実処理は自分で実装する
13年3月17日日曜日
「リターンキーが押された」ことを検知するということについてこれまでのことをまとめておきましょう。
まず、UITextFieldDelegateというプロトコルを使います。UITextFieldDelegateというプロトコルには”textFieldShoudReturn”というメソッドがあり、リターンキーを押されたときに呼ばれます。このメソッドは定義だけされているので、キーパッドを閉じるという処理は委譲先のオブジェクトで行う必要があります。
実装方法
■使用するprotocolの設定
@interface SecondViewController : UIViewController<UITextFieldDelegate>
使用するプロトコルを記載
@interface クラス名:親クラス <使用するプロトコル>
UITextFieldを配置したほうの.hファイルに以下の記述を追加する
13年3月17日日曜日
では実際の実装方法を解説していきましょう
まず、使用するプロトコルを宣言します。UITextFieldを配置した方の.hファイルに以下の記述を記載し、このクラスでは”UITextFieldDelegate”を使いますよ。ということを宣言します。
@interface クラス名 :親クラス <使用するプロトコル>という形式で記載してください。ここでは@interface SecondViewController : UIViewController<UITextFieldDelegate>と記載します。
実装方法
■メソッドの実処理
#リターンキーを押されたときの処理を実装する- (BOOL)textFieldShouldReturn:(UITextField*)textField{ //キーパッドを閉じる処理を実行する [textField resignFirstResponder]; return NO;
} キーパッドを閉じるメソッド
UITextFieldを配置したほうの.mファイルに以下の記述を追加する
13年3月17日日曜日
ではメソッドの実処理の実装していきましょう。UITextFieldを配置した方の.mファイルにリターンキーが押されたことを検知する「textFieldShouldReturn (UITextField*)texField」メソッドを書きます。キーパッドを閉じるには「resignFirstResponder」というメソッドを呼びます。
この状態でコンパイルしてみましょう
キーパッドは閉じたでしょうか???
実はもう一つやることがあるのですが、何でしょうか???ちょっと考えてみましょう。
13年3月17日日曜日
この状態でコンパイルして実行してみましょう。キーパッドは閉じたでしょうか・・・。
実はもう一つやらなくてはならないことがあるのですが、何でしょうか。ちょっと考えてみましょう。
何が足りないのか?
UITextFieldDelegateを使うことにしたものの、textFieldShouldReturnメソッドで行う処理をどこに委譲すればいいかわからない
オブジェクト
「リターンキー押したよ」って誰に処理をしてもらえばいいんだ???
???
13年3月17日日曜日
UITextFieldを使うUITextFieldDelegateをつかうということを宣言したのはいいのですが、textFieldShouldReturnをどこに委譲するかを設定していなかったため、処理が委譲されていなかったのです。textFieldShouldReturnの呼び出しもととしては、誰が処理を行ってくれるかわからなかったため、処理をすることが出来なかったのです。
では、どうすればいいのか??
UITextFieldのdelegate(委譲元)と委譲先のViewControllerを接続する
13年3月17日日曜日
ではどうすればいいのでしょうか。処理の委譲先を設定してあげればいいのです。StoryBoardを開いてみましょう。TextFieldを選択し、コントロールキーを押しながらViewControllerに向けてドラッグします。そうすると図のように黒い窓が出てくると思います。そこでdelegateを選択してください。
ここで何をしているかというと「textFieldShouldReturn」をViewControllerで行ってもらいますよという設定をしているのです。
まとめると・・・
1.UITextFieldDelegateを使うことを宣言
2.textFieldShouldReturnメソッドを実装
3.UITextFieldのdelegateにViewControllerを設定
13年3月17日日曜日
ここまでのことをまとめると、以下のようになります。まず、ViewControllerで「UITextFieldDelegateを使いますよ」という宣言をします。ヘッダファイルの最初に@interface クラス名:親クラス <使用するプロトコル>という形式で記載します。ViewControllerでtextFieldShouldReturnメソッドを実装します。ここでresignFirstResponderというメソッドを呼び、キーパッドを閉じる処理を行います。そして、UITextFieldのdelegateにViewControllerを設定します。StoryBoardの設定を行いましょう。
~このようなViewのことをいいます~
TableView
赤で囲んだ部分:UITableView青で囲んだ部分:UITableViewCell
UITableViewにUITableViewCellが含まれている
13年3月17日日曜日
次にTableViewの作り方について学んでいきます。TableViewの説明をし始めると長くなるので、残り時間も考えて今日は簡単なTableViewの作り方を学んでいき、次回に続きを行います。
TableViewとはどのようなものかというと、図のように複数行の表示を行うViewのことです。 赤で囲んだ部分をUITableViewといい、テーブル全体のことをさします。青で囲んだ部分はUITableViewCellといい、1つの行のことをさします。UITableViewにUITableViewCellが含まれているイメージです。
StoryBoardを変更
TableViewControllerを使うので、削除
13年3月17日日曜日
では、簡単なTableViewを作成していきましょう。新しいプロジェクトを作成してください。プロジェクトを作成したら、デフォルトで作成されるViewControllerを削除します。ViewController.m、ViewController.hとStoryBoardにあるViewControllerを削除してください。削除する際は「Move to trash」を選択していただいてかまいません。
TableViewControllerの作成
UITableViewControllerを継承する
13年3月17日日曜日
デフォルトで作成されたViewControllerを削除したら、TableViewControllerを作成しましょう。ファイルを新しく作成します。作成するときにUITableViewControllerのサブクラスとして作成してください。
StoryBoardを変更
TableViewControllerをドラッグして配置する
作成したクラス名にする
13年3月17日日曜日
ソースコードを作成したら、StoryBoardを変更します。StoryBoardを開いて、右部分のTableViewControllerをドラッグします。ドラッグして配置したら、CustomClassを作成したクラス名にしてください。
この状態で実行してみましょう
何も無い空っぽのテーブルが表示される
13年3月17日日曜日
この状態でビルドしてみましょう。エラーは発生していませんが、何も表示されない空っぽのテーブルが表示されているかと思います。テーブルの外枠しか設定しておらず、テーブルの中身が無いので当然といえば当然です。
これからは中身を表示できるようにしてみましょう。
テーブルの中身を表示する
中身を表示するにはどうすればいいのか??
その前に、TableViewの仕組みについて触れておきます。
13年3月17日日曜日
さすがに中身の無いTableViewを表示するのも寂しいので、中身を表示させるようにしていきます。その前に、少しTableViewの仕組みについて触れていきます。
テーブルの中身を表示するStoryBoardの編集
TableViewCellIdentifier:CellStyle:Basic
TableViewContent:Dynamic:Prototypes
PrototypeCells:1
13年3月17日日曜日
まずStoryBoardの設定を行います。StoryBoardを開き、TableViewを選択してください。その状態で右のメニューを表示します。右から3番目のマークを選択して、図のような状態になるようにします。ContentにDynamicPrototypesを選択し、PrototypeCellsに1を設定してください。ここで何をしているかというと、「このテーブルビューでは行の数を可変にするか固定にするか」ということを設定します。ここでは「Dynamic:Prototypes」を選択しているので、行の長さを可変とし、ソースコード内で行数を変更することが出来るようにしています。PrototypeCellsの設定でテンプレートとなるセルの数を決めています。同じテーブル内でもセルの表示を変更することが出来ます。ここでは同じテンプレートを使いますので、1にします。TableViewの下にあるTableViewCellを選択してください。その状態で右のメニューを開き、図のような設定を行ってください。IdentifierにCellと設定し、StyleにBasicを設定しましょう。Identifierとはテーブルのテンプレートを決めるものです。このテンプレートの名前は「Cell」ですということを示しています。
テーブルの中身を表示する
ソースコードの編集次の3つのメソッドを編集します
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
指定したTableのsection数
指定したSectionの行数
指定した箇所のセル13年3月17日日曜日
次にソースコードの編集を行います。まず、numberOfSectionsInTableViewというメソッドで、指定されたTableに何個セクションがあるかを呼び出し元に伝えます。このメソッドが実装されていない場合は1が返却されます。tableViewnumberOfRowsInSectionというメソッドで、指定されたSectionに何行あるかを呼び出し元に伝えています。このメソッドは必ず実装してください。実装しないとエラーになります。tableViewcellForRowAtIndexPathというメソッドで指定されたIndexPath(セクションと行)のセルを呼び出し元に伝えています。このメソッドも必ず実装してください。実装しないとエラーになります。
テーブルの中身を表示する
図解すると・・・
青い線で囲んだ部分→1つのセクション
黄色い線で囲んだ部分→セクション1つにある行
赤い線で囲んだ部分→1つのセル
13年3月17日日曜日
青い線で囲んだ部分が一つのセクションで、セクション数はnumberOfSectionsInTableViewで指定します。黄色い線で囲んだ部分がセクション内のすべての行で、指定したセクションの行数はtableViewnumberOfRowsInSectionで指定します。赤い線で囲んだ部分が指定したセクションおよび行数に該当する一つのセルで、tableViewcellForRowAtIndexPathで指定します。
テーブルの中身を表示する
ソースコードの編集- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1;}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 2;}
ここではsection数=1
ここでは行数2
13年3月17日日曜日
それではソースコードの編集をしましょう。まず、 numberOfSectionsInTableViewとnumberOfRowsInSectionを編集します。セクション1つで2行表示するようにしましょう。どう指定すればいいでしょうか。。。
テーブルの中身を表示する
ソースコードの編集- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; if(indexPath.row == 0){ cell.textLabel.text = @"上のセル"; } else{ cell.textLabel.text = @"下のセル"; } return cell;}
指定したテンプレートからCellを作成
indexPath.rowで何行目かがわかる
13年3月17日日曜日
それではソースコードの編集をしましょう。次に、tableView cellForRowAtIndexPathを編集します。まず、「 dequeueReusableCellWithIdentifier」でテンプレートからCellを作成します。そして、何行目かによって表示するものを変えます。indexPath.rowと指定すると、何行目かがわかりますので行数に寄って表示するものを変えましょう。UITextViewCellにはtextLabelというラベルが標準でありますので、そちらを変更します。
テーブルの中身を表示する
この状態でコンパイルしてみましょう
このような表示になりましたか??
13年3月17日日曜日
この状態でコンパイルしてみましょう。うまく表示されましたでしょうか?
テーブルの中身を表示する
if文で表示するCellを場合分けしているときりがない・・・
NSArrayを使う→JavaでいうArrayListと同じ使い方をする
13年3月17日日曜日
NSArrayの使い方
NSArray *list = [NSArray arrayWithObjects:@"AAA",@"BBB",nil];
※他にも初期化メソッドはあります
[list objectAtIndex:0]; ※ここでは@”AAA”が返ってくる
arrayWithObjectsで初期化
objectAtIndexで指定したIndexのオブジェクトを取得
countでオブジェクトの数を取得[list count]; ※ここでは2が返ってくる
13年3月17日日曜日
NSArrayの使い方について触れておきます。まず、初期化メソッドを使って初期化します。arrayWithObjectsを使うと指定したオブジェクトでNSArrayを初期化できます。objectAtIndexで指定したIndexのオブジェクトを取得します。countでオブジェクトの数を取得します。
NSArrayは読み取り専用
編集したいときはNSMutableArrayを使う
addObjectでオブジェクトを追加
insertObjectでオブジェクトを挿入
removeObjectAtIndexでオブジェクトを削除
replaceObjectAtIndexでオブジェクトを変更
[list addObject:@”AAA”; //最後にオブジェクトを追加
[list insertObject:@”AAA” atIndex:1]; //1番目にオブジェクトを挿入
[list removeObjectAtIndex:1]; //1番目のオブジェクトを削除
[list replaceObjectAtIndex:1 withObject:@”BBB”]; //1番目のオブジェクトを@”BBB”に変更
13年3月17日日曜日
ただし、NSArrayは読み取り専用のため、編集が出来ません。編集したいときはNSMutableArrayを使います。「Mutable」がついているオブジェクトは編集可能ということです。使い方はJavaのArrayListと似ており、追加、挿入、削除、交換などが出来ます
では、NSArrayを使ってセルの中身を変更してみましょう
13年3月17日日曜日
一定時間ごとに処理を行う
NSTimerを使うと一定間隔で同じメソッドを呼び出すことが出来る
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(increment:) userInfo:nil repeats:YES];
[timer invalidate];
[timer fire];
タイマーを初期化して開始するメソッド
タイマーを止めるメソッド
タイマーを開始するメソッド
13年3月17日日曜日
第2回目でリクエストがあった、「一定時間ごとに値が更新されるプログラム」について説明をします。NSTimerというクラスを使うと、一定時間間隔で同じメソッドを呼び出すことが出来ます。 お渡ししたファイルにNSTimerTestというプロジェクトがありますので、そちらをご覧ください。
一定時間ごとに処理を行う
@selectorって何??→コンパイラに「この引数はメソッドである(SEL型)」ことを示すもの
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(increment:) userInfo:nil repeats:YES];
incrementというメソッドを渡している
13年3月17日日曜日
ここで@selectorについて少し解説します。@selectorとはコンパイラに対して「この引数はメソッド(関数)である」ということを教えています。SEL型と言います。ここで使用しているNSTimerでは自分自身のメソッドを繰り返し呼び出しています。
ご清聴ありがとうございました
13年3月17日日曜日