CS193p 課題5の内容

CS193pのクラスの公式サイトにLecture 11の課題としてAssignment5.pdfがアップされていますので、日本語にしておきます。

キャッシュファイルの作成はいろんなやり方がありそうですが、ヒントでかなり限定されます。

 

課題の内容

目標

前回作成したFlickrの写真を見るアプリのレスポンスをGCDを使って改善する。加えて、マップを追加してユニバーサルアプリにする。

Required Task

1. 前回の課題のアプリの実装を(今回の課題も含めて)Flickrからのデータ取得やファイルシステムとのやり取りをメインスッドで行わないようにする。ユーザインタフェイスはいつでもユーザに対して応答すべきである。(例えば、決してメインスレッドをブロックさせない)

2. ユーザがビュー中の(サムネイル以外の)何かの更新を待っている場合、その間UIActivityIndicatorView(歯車アイコン)を適切な場所に表示する。歯車が回転している間はユーザインタフェイスは完全に応答するべきである。(例えば、ユーザは戻るボタンやタブをタップできて、その待機中状態で画面遷移できること)そして、ユーザインタフェイスはユーザのアクションに応答する以外は決して勝手に画面遷移しないこと。

3. ユーザが見た写真の画像をアプリのサンドボックス内でファイルにキャッシュする。各写真の画像はサンドボックス内で個別のファイルに保存される。キャッシュの制限は10B。この制限に達したら、新しい写真用の空間を開けるためにキャッシュ内の一番古い写真を削除する。アプリは、キャッシュに存在する写真については決してFlickrから画像を取得しないこと。このキャッシュはアプリの起動をまたいで持続していること。

4. メモリ(RAM)内に保持する写真の画像は可能な限り少なくすること。(例えば、画面上にないNSDataやUIImageの写真のオブジェクトへstrongポインタを持たないこと。できれば1つだけの方が良いが(何も参照されていなければ0)、メモリ上に保持する写真の画像データは多くても2つにすること。

5. 写真や場所のリストを表示している部分では、その情報をマップで見る選択肢をユーザに提供すること。
マップ上の各注釈は吹き出しを使って次の情報を表示する。

a) 写真のタイトル or 場所の名前
b) 写真の場合、(少なくとも先頭数語の)写真のdescriptionとサムネイル画像

(FlickrFetcherPhotoFormatSquare)
最初に吹き出しが表示された時にはサムネイルなしでも良いが、出来るだけはやくFlickrからそれを取得してサムネイル表示させること。Required Task #1に注意。

c) ディスクロージャボタンは(ユーザが選択した)写真をフルサイズで表示する

もしくは(ユーザが選択した)その場所の写真一覧を表示する。

6. 画面上にマップビューが表示されたとき、その regionは、全ての注釈がフィットする最小のサイズにセットすること。(それらの周りには見栄えがよくなるような余白をつける)

7. アプリは、iPhoneとiPad両方のユーザインタフェイスをサポートすること。デバイスイデオムを使うこと。

8. デバイス上でアプリを動作させること。

 

ヒント

1. スレッドで処理されている間は、ユーザインタフェイス内で何かを変更することは可能である。(キューにブロックを置くことによって)スレッドに投入した時の状況と行おうとしていることの間でつじつまが合っているか、常に状態をチェックすること。
例えば、ユーザが1つ目にクリックした写真がFlickrから返ってくる前に4つや5つの写真をクリックしたらどうなるか。
どんな表示が賢明か?MapKitのAnnotation Viewの再利用について、以下のヒントを見ること。

2. この課題は、UIViewもしくはUIViewControllerのサブクラスではないObjective-Cのサブクラスを作成する必要がある始めての課題である。(例えば、NSObjectの直接のサブクラスが必要になるだろう)100%必要というわけではないが、この課題のソリューションとしてはそうするのが良い。

3. 緯度のFlickrキーは、@"latitude"で、経度は@"longitude"である。FlickrFether.hにこれを#defineで追加することになるだろう。このキーで取得されるオブジェクトはNSNumberである。CLLocationCoordinate2D内の緯度と経度はdoubleである。

4. NSFileNamagerはディレクトリを作成したり、ファイルが存在するか探したり、ファイルを削除したり、ファイルのサイズをチェックしたりするのに使われる。この課題の1つの目的は、このクラスのドキュメントを見てその使い方を理解することである。

5. キャッシュされた写真の画像データの保存には、NSSearchPathDirectoryから適切なディレクトリを選択するようにすること。そして、サンドボックスを完全にクリアしたければ、シミュレータもしくはデバイスからアプリを削除すること。

6. NSCacheを使っても良いが、必須ではない。(自分でキャッシュ用のクラスを作成する方がシンプルである)どちらの場合でも、アプリが新たに起動するたびにサンドボックス内のものとキャッシュの状態を同期する必要がある。

7. NSFileManagerはスレッドセーフでNSDataの writeToFile:もそうなので、メインスレッドの外でこれらを使うことが出来る。

8. 副次スレッドからはユーザインタフェイスのいかなるメソッドもコールしないこと。(必ずメインスレッドからコール)それを行ったら、上手く動作しているように見えることが多くても、予測不可能な結果になる。

9. MapKitのAnnotation Viewは、それが消えたあとにまた戻って画面上に表示されると再利用されること忘れずに。そのため、サムネイルデータをFlickrから取得する時は気をつけること。

10. アプリにMapKitのライブラリをリンクすることを忘れずに。これはナビゲーションのプロジェクトをクリックして、そしてターゲットの下にあるアプリケーションをクリックして、そしてBuild Setteingタブに行き、Link Binary with Libraryの下の+ボタンを押して追加する。

11. [NSData dataWithContentsOfURL:…]を行う部分にはNSLog()を加えること。このメソッドはとてもコストが高いので、画像が正にユーザが画面に表示するようにリクエストしたものでなければこのメソッドをコールしないこと。マップの全ての吹き出しのサムネイルが一度にFlickrから取得さたのが分かったら特に驚くだろう。ユーザが注釈を選択した時にだけサムネイルを取得するすること。言い換えれば、注釈が作成される毎にFlickrをコールせずに、選択された時だけにする。

12. 美しく見えるようにMapKitの吹き出し内で使う画像サイズをハードコードするのはよい。また、サムネイルの画像がFlickrから取得されるのを待っている時にサムネイルの部分に空のスペースがあってもよい。吹き出しの中に歯車アイコンは必要ない。

13. MKMapViewの中でディスクロージャボタンを機能させるためにperformSegueWithIdentifier:sender:を行う場合、マップビューの中でクリックされている中にはUITableViewCellが含まれていないので、senderとして異なる種類のオブジェクトを渡さなければならない。(そして異なる種類のオブジェクトをprepareForSegue:sender:の中でハンドルしなければならない)

14. ストーリーボードのDocument Outlineは、ビューの階層を操作し、ctrl-ドラッグでアウトレットをセットするのに便利である。たくさんのビューを重ねている時は必要なものをctrl-ドラッグするのが困難である。そこでDocument Outlineが存在するのである。チェックして!

15. UIActivityIndicatorViewをXcodeの中でドラッグして作ったら、hidesWhenStoppedプロパティをセットすることになるだろう。

16. マルチスレッドのコードが本当に機能しているかを確かめる為にネットワーク遅延をシミュレートするものを取り入れるのは良いアイデアである。
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]] を使えば、カレントスレッドを2秒間スリープさせることが出来る。必要ならこれをFlickrFetcher.mの中に入れれば良い。

17. この課題の期限の前にCoreDataを学び始めるが、Core Dataをこの課題では使わないこと。(それは次回に行う)

18. また、この課題の期限の前にObjective-Cのカテゴリー機能をカバーするかもしれないが、使いたければカテゴリーを使っても良い。しかし、必須ではない。使うなら、講義の中で言ったように注意して使うこと。それらは簡単に悪い使い方になりうる。