I phoneアプリ入門 第3回

806 views

Published on

iPhoneアプリ開発勉強会第3回資料です

  • Be the first to comment

  • Be the first to like this

I phoneアプリ入門 第3回

  1. 1. 第3回 iPhone勉強会13年3月17日日曜日
  2. 2. 今後の予定 ・第3回 他の画面の値を変更する方法 MVCモデル、タイマーの使い方 ・第4回 TableView ユーザ操作(タップなど)の検出方法 ・第5回 MapKitを使った地図の表示方法 現在地の取得方法13年3月17日日曜日
  3. 3. 今日のアジェンダ ・前回の復習 ・他の画面の値を設定する ・MVCモデル ・タイマー(一定時間ごとに処理を実行) ・サンプルアプリ作成13年3月17日日曜日今日のスケジュールは以下の通りです。まず、前回の復習を軽く行った後、他のオブジェクトの値変更の仕方およびMVCモデルについて説明した後、時間がありそうだったら、タイマーとテーブルビューの説明をいたします。その後、今日の課題となるサンプルアプリを作成いたします。今日も出来るだけ手を動かすようにしたいと思います。よろしくおねがいいたします。
  4. 4. 前回の復習 ∼以下のようなアプリを作ってみましょう∼ 押すと次の画面へ移動する 動かすとフォントサイズが変 わる13年3月17日日曜日まず、前回の復習をしましょう。前回受講したという前提で、まずはコードを書いてみます。図のようなアプリを作ってみましょう。iPhone上でボタンを押したら次の画面が表示される何のことだかさっぱりわからないと言う方、こっそり教えてください・・・。制限時間は20分とします。
  5. 5. 他の画面の値を設定する view2 view1 fontSize view1でview2のフォントサイズを変えたい view2というオブジェクトにアクセスして フォントサイズを変える13年3月17日日曜日ある画面で設定した値を他の画面へ反映するようにしたいと思うのではないでしょうか。図のようにview1でview2のフォントサイズを変更するという処理をするにはどうすればいいでしょうか。ここでよく思い出してみましょう。Objective-CはJavaと同じオブジェクト指向です。Javaのときはどうしていたでしょうか。。。Hoge hoge = new Hoge();hoge.setMoge(“AAA”);などとというようにオブジェクトにアクセスして値を変更していたと思います。
  6. 6. 他のオブジェクトにアクセスする方法 //View2というオブジェクトを作る (またはどこかからもってくる) view2 View2 *view2 = [[View2 alloc]init]; fontSize //View2というオブジェクトの 「fontSizeを変更する」とい fontSizeを変更する うメッセージを送る view2.fontSize = 12;13年3月17日日曜日Objective-Cでもおなじことです。View2というオブジェクトを新しく作成するかまたはどこかから取得して、View2というオブジェクトに対して「フォントサイズを変更してくれ」というメッセージを送るのです。
  7. 7. 「復習」での具体例 ・ ViewController DetailViewController DetailViewControllerの値を変更したい どちらかをやりたい ViewControllerからDetailViewControllerの値を変更 DetailViewControllerからViewControllerの値を取得13年3月17日日曜日では、復習で行った場合の具体例を見ていきましょう。実装の都合上、ViewControllerで設定した値をDetailViewControllerで表示するというようにします。この場合ですと、ViewControllerクラスからDetailViewControllerに対してアクセスするか、DetailViewControllerクラスあらViewControllerクラスにアクセスすればいいのです。どうすればいいのでしょうか既にViewController、DetailViewControllerで画面を作っているため、オブジェクト自体を新しく作り直す訳にはいきません。いくつかやり方はあるのですが1つ紹介します。
  8. 8. ViewControllerから DetailViewControllerの値を変更する ViewController DetailViewController- (void)prepareForSegue:(UIStoryBoardSegue*)se float(nonatmic) fontSize; gue UILabel *label ViewControllerからDetailViewControllerに遷移すると きに値を変更13年3月17日日曜日先ほど復習で使ったプロジェクトを編集し、ViewControllerで設定したフォントサイズでDetailViewControllerの画面を表示するようにしましょう。まず、StoryBoard画面を開いて、ViewControllerにSliderとStepperを配置し、ヘッダファイルに反映させましょう。そして、ViewController.mに- (void)prepareForSegue:(UIStoryBoardSegue*)segueというメソッドを記載してください。
  9. 9. 2つのViewControllerにアクセスする メソッド- (void)prepareForSegue:(UIStoryBoardSegue*)segueボタンを押したとき(viewを移動するとき)に呼ばれるメソッドUIStoryBoardSegue:2つのViewControllerを行き来するときに使うオブジェクトsourceViewController:(遷移元のViewController)destinationViewController:(遷移先のViewController)13年3月17日日曜日- (void)prepareForSegue:(UIStoryBoardSegue*)segueはボタンを押してViewを移動するときに呼ばれるメソッドで、引数のsegueにはsourceViewControllerという遷移先のViewControllerとdestinationViewControllerという遷移先のViewControllerが格納されています。ここではdestinationViewControllerへアクセスすることで遷移先のViewControllerで保持している値を変更することが出来ます。
  10. 10. 2つのViewControllerにアクセスする メソッド- (void)prepareForSegue:(UIStoryBoardSegue*)segueヘッダファイルに宣言していないのになぜエラーにならない? prepareForSegue は UIViewControllerで宣言されているから13年3月17日日曜日ViewController.mのみに - (void)prepareForSegue:(UIStoryBoardSegue*)segueを記載したと思いますが、ヘッダファイルに宣言しない状態でビルドしてもエラーになりません。なぜかというと、親クラスであるUIViewControllerで宣言されているからです。
  11. 11. ViewControllerから DetailViewControllerの値を変更する- (void)prepareForSegue:(UIStoryBoardSegue*)segue の中身DetailViewController *detailViewController = (DetailViewController*)segue.destinationViewController; detailViewController.label.font = [UIFont fontWithName:@"Helvetica" size:self.fontSize]; DetailViewController型にキャス トしている13年3月17日日曜日- (void)prepareForSegue:(UIStoryBoardSegue*)segueの中身を実装しましょう。segueのdestinatinationViewControllerに遷移先のViewController(ここではDetailViewController)が格納されているので、取得してみましょう。取得したDetailViewControllerのlabelの値を変更してみましょう。こ 状 で ン イ し 実 し す                                                     の 態 コ パ ル て 行 ま 。                                                    
  12. 12. ViewControllerから DetailViewControllerの値を変更する 動かしてみて、フォントサイズは変わりましたか? 実は、これだとフォントサイズは変わらないのです。 なぜでしょう・・・。 なぜか知るために、デバッグしてみましょう。13年3月17日日曜日コンパイルして実行してみましょう。フォントサイズは変わりましたか?変わっていませんね。なぜでしょうか。なぜか知るためにデバッグしてみましょう。Xcodeでブレークポイントを貼ってみましょう。
  13. 13. デバッガを使ってみよう Xcodeを立ち上げて、以下のようにブレークポイントを 設定します。 detailViewController.labelが nilになっている13年3月17日日曜日コンパイルして実行してみましょう。フォントサイズは変わりましたか?変わっていませんね。なぜでしょうか。なぜか知るためにデバッグしてみましょう。画面のようにXcodeでブレークポイントを設定して実行してみましょう。detailViewController.labelがnilになっているのがわかりますか?nilに対して設定しても値は変わらないのです。なので、値が変わらなかったのです。
  14. 14. ここで湧く2つの疑問 ■疑問その1: nilにアクセスして大丈夫なの? (そもそもnilって何) ■疑問その2: 何でdetailViewController.labelがnilなの?13年3月17日日曜日ここで2つの疑問が湧くと思います。まず、nilにアクセスしても大丈夫なのか(そもそも、nilって何?)ということと何でdetailViewController.labelがnilなのかということです。
  15. 15. nilとは? 空のポインタ、無効なオブジェクト ちなみに、値は0 nilはid型の空ポインタで値は0 メッセージを送るとどうなる? →何も送られない。13年3月17日日曜日ここで改めて、「nil」とは何かということを説明します。nilとは無効なオブジェクトのことで、空のポインタです。ちなみに値は0です。デバッガで表示されている値を見てみましょう。0x00000000となっていると思います。javaで言えばNULLと同じようなものなのですが、nilに対してメッセージを送っても落ちるということは無く、何も処理が行われません。なので、detailViewController.labelにアクセスしようとしても、何も行われなかったのです。
  16. 16. 参照(strongとweak) DetailViewController.hの中身 @property (weak, nonatomic) IBOutlet UILabel *label; 弱い参照を表している strong(デフォルト):強い参照。 誰も参照しなくなったらオブジェクトが消滅する weak:弱い参照。 変数スコープを超えるとオブジェクトが消滅する13年3月17日日曜日では、なぜDetailViewControllerの中身がnilだったのでしょうか。DetailViewController.hの中身を見てみましょう。@property (weak, nonatomic) IBOutlet UILabel *labelと書かれているのではないでしょうか。ここで注目していただきたいのは、@propertyの後のweakという文字です。これはオブジェクトが強い参照か弱い参照かを表しています。デフォルトではstrongが設定されています。Objective-Cはリファレンスカウンタ方式をとっており、そのオブジェクトが誰からも参照されなくなったらメモリ上から消えるようになっています。「強い参照」ではオブジェクトが誰からも参照されなくなったらメモリから解放されます。(消滅します)「弱い参照」ではオブジェクトは変数スコープを超えるとメモリから解放されます。
  17. 17. なぜ弱い参照が必要? オブジェクト同士が参照し合っている状態を考えて みましょう。 Object2への強い参照 Object1 Object2 Object1への強い参照 これだといつまでたってもオブジェクトが解放されず、 メモリリークになる13年3月17日日曜日なぜ、弱い参照が必要なのでしょうか。強い参照だけだと困る場合があるのです。図のようにオブジェクト同士が参照し合っている状態を考えてみます。Object1はObject2を参照し、Object2はObject1を参照します。いわゆる、循環参照という状態です。この場合、参照状態が消滅することが無いので、いつまでたってもオブジェクトが残り続けることになります。オブジェクトが残り続けるとメモリリークとなりアプリが落ちてしまう原因にもなるのでさけなくてはならないのです。
  18. 18. なぜ弱い参照が必要? Object2にweakをつけて弱い参照にすると・・・ Object2への弱い参照 Object1 Object2 Object1への強い参照 Object2はスコープを超えると消滅し、Object1に対し ての参照も消滅する13年3月17日日曜日ここでObject2に対してweakをつけて弱い参照にするとどうなるでしょうか。Object1はObject2に対して弱い参照を持っていることになります。Object2はスコープをこえると消滅してしまい、同時にObject1への参照も消滅します。つまり、オブジェクトがいつまでも残り続けるということがなくなると言うわけです。
  19. 19. 例題の場合 InterfaceBuilderでlabelを貼付けることにより DetailViewControllerのviewがlabelを参照 labelへの参照 view label13年3月17日日曜日例題の場合、InterfaceBuilderでlabelをviewに貼付けることで、detailViewControllerのviewがlabelを参照することになります。しかし、viewが消滅したときには貼付けているlabelを見ることはありません。なので、弱い参照としてviewが消滅すると同時にlabelも消滅させてしまうのです。
  20. 20. では、どうすればいい? DetailViewController.hに以下を追加します。 @property (nonatomic)float fontSize; そして、DetailViewController.mに以下を追加します Viewを表示するときに呼ばれ ・viewWillAppear るメソッド self.label.font = [UIFont fontWithName:@"Helvetica" size:self.fontSize]; さらに、ViewController.mに以下を追加します ・prepareForSegue detailViewController.fontSize = self.slider.value;13年3月17日日曜日ではどうすればいいでしょうか。labelを直接変更せず、フォントサイズを渡してあげればよいのです。DetailViewControllerでは受け取ったフォントサイズを反映します。DetailViewControllerの親クラスであるUIViewControllerでは、viewを表示する直前にviewWilAppearというメソッドが呼ばれます。そこでlabelに渡されたフォントサイズを反映させてあげればいいのです。さらにViewController.mのprepareForSegueではDetailViewControllerで定義したfontSizeの値を変更しましょう。ちなみに、fontSizeはオブジェクトではなくプリミティブな値なので、メモリは自動解放されます。なので、strongやweakをきにする必要はありません。
  21. 21. ここまでのまとめ ・他のオブジェクトの値の変更 ・デバッグ ・nilについて ・強い参照と弱い参照13年3月17日日曜日無事に動いたでしょうか。ここまでのおさらいをします。まず、他のオブジェクトに対して値を変更する方法を勉強しました。デバッガの起動方法も触れましたね。nilが何かということも勉強しました。強い参照と弱い参照にも触れました。ここでやったことはかなり難しいです。今すぐにすべてを理解するのは大変なので、開発がある程度で切るようになったらもう一度見直していただけるとうれしいです。
  22. 22. MVCモデル ここで、他の値も設定するようにプログラムを 変えてみましょう。 数カ所だけならまだしも、何個も変更する値が あるとめんどくさい →そこでMVCモデルを使う13年3月17日日曜日今までの話で、画面で設定したものを他の画面へ反映する方法を学んだので、他のパーツを追加し、変更した値を反映するようにしましょう。いちいちすべての値を渡すのは大変です。一つのオブジェクトとしてまとめた方が楽です。そのような要求に応えてくれるのがMVCモデルです。これからMVCモデルについて勉強していきます。Javaなどでも画面で設定したものをデータオブジェクトに保持するなんてことを行っているかと思います。Objective-Cでも同じです。iPhoneアプリの開発ではMVCモデルに基づいて開発します。釈 に説法かも知れないですが、MVCモデルについておさらいします。Modelでデータの保持およびデータの操作を行います。ViewでModelのデータを画面に表示します。Controllerでユーザの操作の受付およびモデルの操作を行います。Viewに対するControllerということでViewControllerを使っていた訳です。
  23. 23. MVCモデル Model データおよびデータの操作 View Controller Modelのデータを ユーザ操作の受付 画面へ表示 モデルの操作13年3月17日日曜日Objective-Cでも同じです。iPhoneアプリの開発ではMVCモデルに基づいて開発します。釈 に説法かも知れないですが、MVCモデルについておさらいします。Modelでデータの保持およびデータの操作を行います。ViewでModelのデータを画面に表示します。Controllerでユーザの操作の受付およびモデルの操作を行います。Viewに対するControllerということでViewControllerを使っていた訳です。
  24. 24. Modelを作成してみよう ・会員(Member)というモデルを作成 ∼モデルのデータ∼ ・会員番号   変数名:memberId 型:int型 ・会員名  変数名:memberName 型:NSString型 このモデルを実現するオブジェクトを作成するには?13年3月17日日曜日ViewとControllerについては既に作成しているので、今度はViewで入力したデータを保持するモデルを作成しましょう。例えば会員(Member)というモデルを作成する例を考えてみます。モデルの中身は、int型の会員番号とNSString型の会員名とします。この場合、どのようにオブジェクトを作成するにはどうしたらいいでしょうか。
  25. 25. Modelを作成してみよう 必要なもの ・.hファイル(Model.h) ・.mファイル (Model.m) ・.hファイルの中身 @property(nonatomic,strong) NSString *memberName; @property(nonatomic)int memberId;13年3月17日日曜日必要なものは.hファイルと.mファイルです。メニューのFile→New→Fileを選んで新しいファイルを作成します。Objective-C Classを選択して次に進んでください。ClassにはMember、SubClassにはNSObjectを記載して保存してください。そうすると、Model.hとModel.mが作成されます。Model.hにmemberNameとmemberIdを宣言してください。@propertyをつけるとgetterとsetterが作成されるので、特にModel.mの記載はいりません。
  26. 26. シングルトン どこからでもアクセスできるシングルトンにします。 ・Model.hに以下の記載を追加 +(Member *)sharedInstance; ・Model.mに以下の記載を追加 static Member *member = nil; @implementation Member +(Member *)sharedInstance{ if (member == nil) { member = [[super alloc]init]; } return member; }13年3月17日日曜日このままでもいいのですが、どこからでもアクセスできるようにシングルトンにします。(データを外部ファイルに保存していないので)Model.hには以下のように記載してください。+(Member *)sharedInstance;+というのは、クラスメソッドであるということです。つまり、オブジェクトではなく、クラスに対してメッセージを送るということです。ここではMemberというクラスに対してsharedInstanceというメッセージを送るとMemberがたのオブジェクトが返ってきます。Model.mファイルにはsharedInstanceメソッドの実装を行います。まず、staticをつけることにより、ファイル内だけで有効となります。(ほかのオブジェクトからアクセスできないようになります)そして sharedInstanceが呼ばれたときは、nilであるかどうかチェックをして、nilだった場合のみ初期化します。
  27. 27. 値の参照方法 値を参照するには以下のように記述します [Member sharedInstance]. memberName; これでMember型のオブジェ クトを取得 取得した値を表示させてみましょう13年3月17日日曜日Member型のオブジェクトに設定した値を参照するには[Member sharedInstance]を使ってオブジェクトを取得します。取得したオブジェクトの値を参照してください。MVCTestというプロジェクトをに詳細のコードを記載しておりますので、見てみましょう。
  28. 28. 一定時間ごとに処理を行う NSTimerを使うと一定間隔で同じメソッドを呼び 出すことが出来る [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(increment:) userInfo:nil タイマーを初期化して開始す repeats:YES]; るメソッド [timer invalidate]; タイマーを止めるメソッド [timer fire]; タイマーを開始するメソッド13年3月17日日曜日ここで前回リクエストがあったので、「一定時間ごとに値が更新されるプログラム」について説明をします。NSTimerというクラスを使うと、一定時間間隔で同じメソッドを呼び出すことが出来ます。お渡ししたファイルにNSTimerTestというプロジェクトがありますので、そちらをご覧ください。
  29. 29. 一定時間ごとに処理を行う @selectorって何?? →コンパイラに「この引数はメソッドである(SEL 型)」ことを示すもの [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(increment:) userInfo:nil repeats:YES]; incrementというメソッドを 渡している13年3月17日日曜日ここで@selectorについて少し解説します。@selectorとはコンパイラに対して「この引数はメソッド(関数)である」ということを教えています。SEL型と言います。ここで使用しているNSTimerでは自分自身のメソッドを繰り返し呼び出しています。
  30. 30. 今日のまとめ ・他のオブジェクトの値の変更 ・MVCモデル ・タイマーの使い方13年3月17日日曜日では、今日の課題に入る前におさらいをしましょう最初に他のオブジェクトの値の変更する方法を勉強しました。そして、MVCモデルを使って色々な画面から値を参照できるようにしました。おまけにタイマーの使い方を勉強しました。
  31. 31. 今日の課題13年3月17日日曜日では、今日の課題です。このようにボタンを押したら項目の編集を行い、編集結果を反映できるようにしてみてください
  32. 32. ご清聴ありがとうございました13年3月17日日曜日

×