KLab若手エンジニアの これなぁに?

KLab株式会社の若手エンジニアによる技術ブログです。phpやRubyなどの汎用LLやJavaScript/actionScript等のクライアントサイドの内容、MySQL等のデータベース、その他フレームワークまで幅広く面白い情報を発信します。

2010年11月

iPadで動く電子書籍アプリを作ってみる(2)

こんにちは、ponpoko1968です。人間でいうと20代後半に相当します。 少し間が開いてしまいましたが、第2回はページイメージの表示を行います。

1 ページ表示ビューの作成

まずページのイメージを表示するビューを作成します。(紛らわしいですが便宜上ページビューと呼ぶことにします。)Xcodeから、[ファイル][新規ファイル]を選択し、必要なオプションを指定(下図参照)して、「PageViewController」を作成します。
新規クラスの追加


PageVewController.hを開いて、下記のように定義を追加します。
@interface PageViewController : UIViewController <UIScrollViewDelegate>{
  IBOutlet UIView*      contentView_;
  Document*             document_;
}
@property (nonatomic,retain) Document*          document;
まず、UIScrollViewDelegateプロトコルを実装し、画面の拡大/スクロールに対応します。UIViewクラスのcontentViewメンバを追加します。IBoutletキーワードを前につけることで、Interface Builder(以下IB)から認識されるようにします。

1.1 nibの作成

次にPageViewController.xibをダブルクリックしてIBを立ち上げ、nibにUIScrollViewを追加します。下図のドキュメントウインドウの状態のように、スクロールビューのサブビューとしえViewが来るようにしてください。 (Viewをドラッグして、Scroll Viewの上でドロップすればOKです。)


nibとPageViewコントローラのメンバの結びつきを変えるため、IBのドキュメントウインドウでFile'sOwnerを選択し、インスペクタを表示します。


contentView_ → View view → Scroll View にそれぞれ結びつければ、IBを使っってのPageViewコントローラの準備は完了です。

2 ページビューの表示

2.1 Documentクラスの作成

ユーザが選択した文書をページビューが表示するため、文書前回Bookshelfクラスを定義し、アプリにインストールされた文書ファイル名を返すメソッドを定義しましたが、今回はBookshelfクラスにDocumentクラスの作成するメソッドを追加します。文書ファイルへのパス名を送ると対応するDocumentオブジェクトを返すメソッドを定義します。
-(Document*) documentWithPath:(NSString*)path {
  Document* doc = [documents_  objectForKey:path];
  if( doc ){
      return doc;
  }
  doc = [[Document alloc] initWithPath:path];
  [documents_  setObject:doc forKey:path];
  return doc;
}

2.2 画面遷移

文書一覧画面で、ファイル名をタップするとページビューに遷移して、選択したファイルを内容を表示するようにします。ファイル名がタップされたことをハンドリングするには、UITableViewDelegateプロトコルのtableView:didSelectRowAtIndexPath:をインプリメントします。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  // Bookshelfインスタンスを取得
  Bookshelf* shelf = [Bookshelf sharedBookshelf];

  // nibファイルの内容に基づいてページビューを作成
  PageViewController* pageVc = [[PageViewController alloc] initWithNibName:@"PageViewController" bundle:nil];

  // pageViewにDocumentオブジェクトをセットする(documentプロパティが暗黙的にretainする。)
  NSString* path = [[shelf documentNames] objectAtIndex:indexPath.row];
  pageVc.document = [shelf documentWithPath:path];

  // 画面遷移を行う
  [self.navigationController pushViewController:pageVc animated:YES];

  // ビューコントローラをnavigationControllerに渡したので所有権を放棄する
  [pageVc release];
}
この時点でiPhoneシミュレータで実行すると、左から右に画面が切り替わって、真っ白な画面が表示されると思います。 次はいよいよ、ページの表示を実装します。

3 ページクラスの定義

ここで文書に含まれるページを抽象化したPageクラスを導入します。 PageクラスはDocumentクラスに包含されるクラスなので、Documentが保持するページ数、すなわちページオブジェクトの数を返すメソッド、そして、ページ番号を指定してPageオブジェクトを取得するメソッドを定義します。

4 PDFイメージのレンダリング

PDFページのレンダリングは、Quartz(Core Graphics)に含まれるPDF関連のAPIを使います。APIを用いて画面に描画する流れとしては、
  1. PDFファイルをオープン
  2. Core GraphicsのPDFページオブジェクトを取得
  3. オフスクリーンバッファにPDFページオブジェクトを描画
  4. オフスクリーンイメージを画面に表示
という手順で行います。このあたりの処理は、Appleの公式ドキュメント「Quarts 2D Programming Guide」の「Opening and Viewing a PDF」節で解説されているので、併せて読んでみてください。 まず、PDFファイルを開きます。
 CFURLRef url = CFURLCreateWithFileSystemPath (NULL, (CFStringRef)self.document.filePath,
kCFURLPOSIXPathStyle, 0);
CGPDFDocumentRef pdfDocument = NULL;
pdfDocument = CGPDFDocumentCreateWithURL (url);
CFRelease(url);
所定のページを開きます。
 page =  CGPDFDocumentGetPage ( pdfDocument, self.nombre );
CGPDFPageGetBoxRect()でページの矩形を取得します。
 CGRect aRect = CGPDFPageGetBoxRect (page,kCGPDFCropBox ); 
このとき、第2引数で、kCGPDFCropBoxを指定すると、PDF形式に指定されたcropbox属性の値を返してくれます。PDFではページ全体の大きさとは別に、ページの周囲の余白を切り取った矩形をページのcorpbox属性として別途格納できます。ちなみに、pdf編集ソフトなどでは、自炊したPDFに後からcropbox属性を追加することが出来ます。余白を切り取ることで画面上の文字が大きく表示でき、見やすくなります。
 CGContextRef context = [self createBitmapContextWithSize:CGSizeMake(aRect.size.width*scale,aRect.size.height*scale)]; 
メモリ上のビットマップにQuartzのPDF描画関数を用いてレンダリングするため、ページサイズの情報を元に描画コンテキストを作るcreateBitmapContextWithSize:メソッドを呼び出します。(ソースコード参照)
 CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, aRect, 0, true);
CGContextConcatCTM( context, pdfTransform ); 
主にページの印刷方向を指定する目的で、各ページにはアフィン変換行列が指定されているので取得し、ページを描画する前に、設定します。 CGContextDrawPDFPage()で、描画コンテキストにレンダリングします。
 CGContextDrawPDFPage( context, page ); 
CGBitmapContextCreateImage()でCGImageオブジェクトに変換します。
 image = CGBitmapContextCreateImage ( context ); 
CGPDFDocumentは取得したページオブジェクトを内部でキャッシュするらしく1、iOSでオープンしたドキュメントはページ取得の都度オープン・クローズした方が良いようです。
 CGPDFDocumentRelease(pdfDocument); 

1 Life is Beutiful:iPadアプリ作成日誌: PDF関連APIのバグについてを参考にさせていただきました。大変助かりました。

5 PDFイメージの表示

イメージを画面に描画するにはいくつか方法がありますが、今回はCore Animationを用いた方法を使いました。 コードは下記のようにきわめてシンプルです。
-(void) renderPage {
Page* page = [document_ pageWithNombre:document_.currentNombre];
CGImageRef ref = [page imageWithScale:2.0];
[[contentView_ layer] setContentsGravity:kCAGravityResizeAspect];
[[contentView_ layer] setContents:(id)ref];
}

ビューからCore Animationのデフォルトレイヤーを取得し、レイヤーにsetContents:メソッドで、イメージを設定するだけです。 レイヤーのsetContentsGravity:メソッドでkCAGravityResizeAspectを指定することで、ページのアスペクト比を維持しつつビューいっぱいにページイメージが表示されます。下のスクリーンショットの例では、新書を自炊したものを表示しています。新書は縦に細長い判型のため、左右に生じた部分は黒く表示されています。これはページビューの背景色がそのまま出ています。開発に置いては、背景色を白以外の色にしておいた方がわかりやすいですが、リリース版では白にしておくとこのような縦長、もしくは横長の判型でも比較的違和感なく表示されると思います。


6 まとめ

今回はPDFファイルからページイメージをオフスクリーンバッファにレンダリングしたのち、画面へ表示するまでを説明しました。 PDFのページイメージの生成はメモリ、処理時間両方についてコストのかかる処理です。特に自炊の場合はページ全体がビットマップイメージとして保存されているのでなおさらです。この連載ではDocument,Pageオブジェクトと一緒にページイメージを永続化することで、処理の高速化を図る方法を解説する予定です。 次回はタップイベントを処理して、複数ページの表示を実現する方法を説明します。 今回より、launchpadというコードリポジトリサイトを用いてソースを公開します。
bzr branch -r article-2-release lp:~klabrd/jisuireader/trunk article-2-release
で取得してください。

7 前回までの目次

iPadで動く電子書籍アプリを作ってみる(1)

ソースコードをkindleで読もう

こんにちはtakada-atです。 わたしはkindleユーザーで、毎日通勤電車の中でkindleを使ってます。 持ち歩くのが難しい重い技術書などもkindleなら簡単に持ち運べて、どこでも読めて、しかもどこでも購入できるので大変重宝してます。英語コンテンツ以外が少ないのが難点ですが、勉強と割り切って英語中心に読んでます。 慣れてくると欲がでてきて、「ソースコードもkindleで読みたい!」と考えるようになりました。 ソースコードをkindle用の形式に変換してくれるツールを探したんですが、無かったのでつくってみました。




https://github.com/takada-at/sc2epub

■しくみ

  • epub形式のファイルはxhtmlに、表紙・目次などのメタデータを追加して、zip圧縮したものです。
  • そこで sc2epub では、ソースコードを PREタグでかこんで、xhtml に変換し、目次など、必要なファイルを追加します。
  • またMakefile を生成し、zip 圧縮や kindle用のmobiフォーマットへの変換を簡単にします。
  • epub から mobiファイルへの変換には、amazon公式のkindlegen を利用できます。
  • http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000234621

■インストール


$ gem install sc2epub

■使い方

sc2epub <変換したいソースコードのディレクトリ> <生成されるディレクトリ> <プロジェクト名> という風に使用します。 例として readline-5.2 のソースを変換します。 "~/src/readline-epub" というディレクトリを作成します。

$ sc2epub ~/src/readline-5.2 ~/src/readline-epub readline
$ cd ~/src/readline-epub
$ make

ここまでで readline.epub というファイルが生成されます。 mobi ファイルを作成するためには先に kindlegen コマンドをパスの通った場所にインストールしておく必要があります。 kindlegen コマンドは以下から入手してください。 http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000234621 kindlegen コマンドがあれば、以下のように mobi ファイルを作成できます。

$ make kindle

readline.mobi というファイルが作成されるので、あとはこちらを kindle にコピーして読むことができます。

■使用感など

ページの端で折り返されるので、若干読みづらいですが、読めないことはないです。 kindle側でtypeface をcondensed に変更し、フォントサイズを小さくすると読みやすくなるようです。

■ 参考資料

epubフォーマットについては、以下のページなどを参考にしました。

パーフェクトPHP書評

こんにちは、blog登場3回目のnakazawa-kです。書きかけのAndroid記事よりも先になってしまったのですがせっかく献本を頂戴したということで、発売日にはレビューを載せたいなと思い少々駆け足で読んだ「パーフェクトPHP」社内回し読み2人目の書評(?)です。 本にどのようなことが書かれているか、についてはAmazonに掲載されている目次でも見ていただけば大体分かると思いますので、ここでは「どんな人が読むと、どんなことが得られそうか」「nakazawa-k的に気になったトピック」を主に取り上げます。他の切り口は社内外の他の方にお譲りします。 一言でざっくりまとめると「PHPでプログラムを書く人、書いている人は斜め読みでもよいので一読すると、抜けているポイントを補間出来たり、自分の理解度を把握することが出来るので是非読むべき」という感じです。この本から得るものは何も無いという方は、それはそれでひとつの指標として捉えられるのではないでしょうか。その上で、PHPからしばらく遠ざかっていたけれどまた書くことになった、という時にでも『PHPのクセ』を思い出すためのツールとして有効なのではないかな、と考えています。 以下、より具体的に書いていきます。 第二部、PHPの言語仕様については、既にPHPを用いてアプリケーション開発を行っている方もざっと一読をお薦めします。何か抜けている箇所があるかもしれません。PHPは詳細な仕様をきちんと認識していなくてもコードをガリガリ書くと案外動作してしまうので、場合によってはずっと知らないままになってしまうかもしれません。言語仕様をきっちりと把握していないと思わぬところでハマったり、再現性の悪いバグに悩まされたりします。一度整理しておくのは非常に有意義でしょう。 第三部、第四部、第五部は「PHPでWebサービスを作り始め、ひとまずゴリ押しで動かすにはどうするのか、その後保守しやすくPHP的にあるべき姿へとコードを変更するためにはどのようにすべきか、サービスとして公開するにあたりどのような点に注意を払いセキュリティを保つべきであるのか」という、サービス開発者の成長フローとも言えるものをまとめています。 特に第7章からのWebサービス向けフレームワーク設計と実際のディレクトリレイアウトやコードへの落とし込みと、それを用いたアプリケーション構築までを、ある程度思考フローを追いかけて記載されている部分は「フレームワークを使ってるけど、それらがどのように実装されているのか、そしてそれはなぜなのかは分からない。知りたい」という意識を持たれている方はステップアップのために是非読まれることをお薦めします。コンパクトでそこそこ使いやすいフレームワークをPHPで構築するためにどのような要素が必要か、どの程度柔軟性を持たせるべきか、どのようなことに注意を払う必要があるのか、という思考をある程度追体験することが出来るように思います。 終盤の章はPHPに慣れていない人に「こういうのがあるんだー」と、とりわけ文字列操作や配列操作関数がやたらと充実していることを知ってもらうための章立てです。実際にコードを書く段階になって既存関数を自分で書かずに済み、取り組むべきロジックに注力出来る、という意味で有用ですが、既にPHPをある程度触っている人は「何か、知らないものないかな」とざっくり眺める程度でOKでしょう。 ちなみにこのあたりはリファレンス的な内容であることも影響していると考えられますが、多少失速してしまった感があります。他の章についているPHP5.3以降対応の注記が無くなってしまっている(例えばDateIntervalは5.3から、DateTimeクラス自体は5.2にもあるがDateTime::diff()は5.3から)ので、実際に記載の関数/メソッドを使われる際には、リファレンスで確認されることをお薦めします。12章冒頭で書かれているように「PHPのマニュアルはよく出来てる、ちゃんと読もう」ということです。 蛇足ながらPHP5.2.xは現状予定では5.2.15で終了、ということになっています。つまり、そろそろPHP5.3.xへの移行を本格的に考えるべき時期に来ているのですが、まだまだ世の中のサーバでPHP5.3.xが使えない環境が多い上に既存5.2用コードの一部が動作しないことを考えると、依然としてバージョンごとの関数/メソッドサポートについては気を使う必要があります。
= 雑多なトピック = PHP5.2.xな世界に居る人から見たPHP5.3.xの魅力 ・三項演算子の省略記法 $result = func() ? func() : 'default'あるいは$result = ($ret = func()) ? $ret : 'default';と書かざるを得なかったコードが $result = func() ?: 'default'; と書けるようになった。これは幸福度高いです。 ・無名関数 説明不要ですね。使い方によってはコードがカオスになる懸念はありますが、便利にさっくり書ける場面が増えそうです。 ・Nowdoc
$var = <<<'EOM'
text
text
EOM;
シングルクォートでバウンダを指定するという記法がとても残念な感はあるのですが、式を書けない場所にも変数展開無しヒアドキュメント(残念ながら、私はほぼ使わない)を置けるのは嬉しい人がいそうな感じです。一方、constにarrayを定義出来ると嬉しいのですが、残念ながらそれはPHP6.0まで対応されません(6.0の話はやめろーという声が聞こえてきそう)。 本書でも記載されている自動キャストの挙動は様々なところでネタにされているように、PHPでエンバグの原因になる要素のひとつです。厳密比較のほうが速度的なメリットも得られるのですが、全てを厳密比較で行うためにはある程度入力時のキャスト等に労力をかける必要があるため、正しい知識を持った上で場合によって使い分ける必要があります。 本書中に可変変数など、様々な便利機構が記載されていますが、それらについてどの程度コストがかかるかという点については触れられていないので、自ら計測する必要があります。これは処理前後でのmicrotime()を用いた時間計測(実際には数十万回ループにすると思いますが)および使用前後でのmemory_get_usage()を用いた(あるいはXdebugでのトレース出力)メモリ消費量計測によって簡単に取得出来るので、新しい仕組みを使ってコードを書く際には習慣付けると良いでしょう。 本書のコラムにてPHPに限らず、ある言語自体のソースコードが手元にある場合、それをよく知るための良い手掛かりとしてテストコードを読む、というのが挙げられています。PHPのテストコードはPHP自身で書かれていることが多いため仮にCが読めなくとも取っつきやすい、ということです。未知のものに対するアプローチとして面白いものだと感じ、実践してみようと思います。 うっかり知識から抜けていたポイント。 foreachにて要素参照を使うことが出来る。
foreach ($list as &$elem){
}
で参照をそのまま使える。ただし、ブロックを抜けた後での変数破壊コードを埋め込んでしまう恐れもあるため、ループ抜けたらunsetしておくのが無難。外部ソースから取得した配列データを事前に型変換した上でAPCに放りこむ、などの用途で便利ですね。
$list = fetch_data();
foreach($list as &$element){
    $element['id'] = (int)$element['id'];
}
...

勝手に正誤表(既に指摘されてるのを知っている箇所は除いているので完全なリストではありません) 意味的なものではなく、表記的なもののみ。 p.267:設定するして→設定して p.279:処理が完了ら→処理が完了したら p.309:ログイン状態のみ→ログイン状態でのみ、が一般的かな p.373:RFCに準拠しないも→RFCに準拠しないアドレスも

iPadで動く電子書籍アプリを作ってみる(1)

こんにちは、ponpoko1968です。 最近、「自炊」と言う言葉がはやっているのをご存じでしょうか?高性能で使いやすいドキュメントスキャナーが登場したことで、紙の本を断裁して、スキャンすることで電子化しPCやiPad,kindleのようなタブレットで読むことが流行しています。 私も、日々会社と家を往復する日々をすごすため、たくさんの重い技術書を持ち歩けず、何か疑問があって、調べたい、勉強したいというときに、すぐ手元に技術書があって、どこでも参照できたらなぁ。。。と常々思っていました。 そんな中、「自炊」とiPadの登場です。筆者も早速重い技術書をスキャンして、iPadで持ち歩くようになりました。おかげで過去の雑誌の記事や、解説書など、紙媒体の状態では重くて両手で持つことすら出来ない量の資料を1kgにも満たないiPadの中に入れて持ち運び出来るようになりました。 これら資料は、iPad向けに数多くリリースされている電子書籍リーダアプリを使って読んでいます。それぞれすばらしい機能があるのですが、なかなか筆者のニーズにはぴったり来るものがないなぁ、、、と思っていると、むくむくと「車輪の再発明」欲がわいてきてしまいました。そこで、せっかくだから(笑)電子書籍アプリの開発に挑戦してみることにしました。 今回の記事ではアプリのプロジェクトの構成の説明にはじまり、文書ファイルの一覧までを実装します。

2 コンセプト

私が考えた電子書籍リーダーのコンセプトを一言で言うと、「勉強やアウトプットが目的で読書する人のためのリーダー」ということになります。 というわけで自分で自分にRFPを出すと、こんな感じです。
  • 書籍データは(主に自炊した)PDFファイルをターゲット
    • PDFはリフロー型(*)の書籍形式ではないので、部分拡大機能を充実させる
  • 重要な部分などを簡単にクリップすることが出来、クリップした内容はローカルやクラウド上でコレクションできる
  • 地下鉄など電波が届かない場所で読むことも多いと思うので、機能実装においてはオフライン状態でつかうことも意識する
  • 描画・データ管理を工夫して高速・快適なブラウジングが出来るようにする
  • せっかく作るので、風呂敷を広げすぎない程度に、自分の想像力の範囲で、抽象化を意識したクラス設計にはする
当面の目標として、下記のような画面構成を考えます。

3 方針と設計

早速ですが設計に入ります。 今回のアプリはスタンドアロンのGUIアプリなのでシンプルなMVCに分解して考えます。 モデル系のクラスとしては、
  • BookShelfクラス 書籍データ全体を保持するSingletonなクラス。ディスクもしくはローカルRDBMSへのアクセスを抽象化する。永続化にはCoreDataを使ってみる予定
  • Documentクラス 個々の書籍データを保持するクラス。アプリで主に使う書籍データの実体はPDFファイルだが、目次やクリップ情報など、書籍単位で管理するデータの保持
  • Pageクラス ページの情報、ページイメージのキャッシュなど付加的なページのデータを保持。 という風に、 情報の粒度を基準にまとめることにします。

4 プロジェクトの作成

Xcodeでプロジェクトを作成します。[ファイル]→[新規プロジェクト]→[新規プロジェクトのテンプレートを選択:]で、「Navigation-Based Application」を選びます。実装に入る前に、忘れないように若干の設定変更を行います。

4.1 ファイル転送の設定

文書ファイルのアプリへの転送には、いろいろな方法が考えられますが、まずは今回はもっとも手っ取り早い、iTunesから転送する方法をサポートすることにします。 iTunesから文書ファイルをアプリへ転送できるようにするには、プロジェクトファイルの中の<アプリ名>-Info.plistに「Application supports iTunes file sharing(UIFileSharingEnabled)」と言うキーを追加して、その値を「YES」に設定します。 すると、iTunesにiPadを接続して、iPadを選択すると、[App]タブの画面下部にファイル転送用の画面が出現します。転送先のアプリのアイコンを選択して、PDFファイルをドラッグ&ドロップすれば即座にファイルが転送されるようになります。

5 Bookshelfクラスの実装

Bookshelfは転送された文書全体を管理するクラスです。シングルトンとして設計してアプリ全体からアクセスできるようにします。シングルトンなBookshelfのインスタンスはstatic変数としてクラスの実装内部で宣言します。
static Bookshelf* theBookshelf = nil;
常に単一のインスタンスを返す、sharedBookshelfというクラスメソッドを定義して、各Viewクラスはこのメソッドを起点に文書データにアクセスします。
  + (Bookshelf*) sharedBookshelf {
  if( nil == theBookshelf ){
    Log(@"%s:%d ", __FUNCTION__, __LINE__ );

    theBookshelf = [[Bookshelf alloc] init];
    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:
                                            [Bookshelf class]
                                          selector:
                                            @selector(sharedBookshelfWillClose:)
                                          name:
                                            UIApplicationWillTerminateNotification
                                          object:
                                            app];
  }
  return theBookshelf;
}
シングルトンの実装で課題となりがちなのが、シングルトンインスタンスの解放のタイミングですが、今回は、ノーティフィケーション機構を使って解放するようにしました。上記コードのように、アプリケーションが終了するタイミングで、[Bookshelf class]で取得されるクラスオブジェクトに、sharedBookshelfWillClose:メッセージを送ってもらうよう、ノーティフィケーションセンターに登録しておきます。呼び出されるsharedBookshelfWillCloseの中身は、現状はシンプルにインスタンスを解放するだけです。
+ (void) sharedBookshelfWillClose:(NSNotification*)notification {
 notification = notification;
 // シングルトンインスタンスの開放
 // UIApplicationのUIApplicationWillTerminateNotificationノーティフィケーションで実行
 Log(@"%s:%d ", __FUNCTION__, __LINE__ );
 if( theBookshelf)
   [theBookshelf release];
 }

6 文書の列挙

Bookshelfクラスはその名の通り文書を保持するクラスなので、下記のメソッドを定義します。
  • (NSInteger )documentsCount 文書数を返します。
  • (NSArray*) documentNames 文書の名前を格納したNSArrayを返します。
  • (Document*)documentWithName 文書の名前で指定されたDocumentsクラスのインスタンスを返す。 今回のアプリではアプリのバンドルのDocumentsディレクトリの直下にフラットに配置することにして、ファイル名を主キーにして、文書を識別することにします。アプリに転送された文書ファイルを列挙する処理については、サンプルコードのloadDocumentsメソッドを参照してください。

7 Documentsクラスの実装

DocumentクラスはおのおののPDFファイルへのアクセスを抽象化します。 実装と行っても、現段階のコードではファイル名を保持するだけのものなので、至ってシンプルに、2つのメソッドしか持ちません。
@interface Document : NSObject {
  NSString* filePath_;
}
-(id) initWithPath:(NSString*)path;
@property ( nonatomic, readonly, getter=getName ) NSString* name;

8 文書リストの表示

BookshelfViewControllerにコードを追加します。プロジェクト作成時点で、XCodeが生成する最初のビュー画面はすでにUITableViewになっているので、このビューをそのまま使います。
このビュー、プロジェクトの作成時のデフォルトはRootViewControllerという名前になっていますが、サンプルコードではBookshelfViewControllerという名前に変更しています。クラス名の途中変更はXCodeのリファクタリング機能を使うと便利です。
UITableViewで内容を表示するために必要な3つのメソッドの実装を書きます。 numberOfSectionsInTableViewはテーブルのセクション数を指定します。今回はテーブルをセクション分けて表示しないので、常に1を返します。
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
tableView:numberOfRowsInSection: でbookShelfが持つ現在の文書数を返します。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
   Bookshelf* shelf=   [Bookshelf sharedBookshelf];
   Log(@"%s:%d %d", __FUNCTION__, __LINE__,[shelf documentsCount] );

   return [shelf documentsCount];
}
tableView:cellForRowAtIndexPath:でファイル名を表示するセルを作って返します。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";
   Bookshelf* shelf=   [Bookshelf sharedBookshelf];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    cell.textLabel.text = [[shelf documentNames] objectAtIndex:indexPath.row];

    return cell;
}
ちなみに、iPhoneシミュレータ上のアプリにPDFファイルを転送するには、下記のコードで取得されるパスに、直接ファイルをコピーすればOKです。 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *aDirectory = [paths objectAtIndex:0];
これでようやく、文書のリストが画面表示されるようになりました。 次回はPDFページの表示を行います。 サンプルコードはこちら

ライブドア様、KLab合同勉強会を開催しました

こちらのブログでは初めましてになります。 yokogawa-kです。 このブログで前回勉強会の報告をさせていただだくようになってからすでに半年が過ぎ、朝夕もめっきり冷え込む季節になりましたね。 みなさん風邪などひかないようにしっかりと体調管理しましょうね。 さて、今回は10/22にライブドア様と合同勉強会を開催させて頂きましたので、その様子を報告させていただきます。 KLabセッション(1) 「FlashLiteとわたし」 まずは弊社の高田による発表です。
takada-at




ソーシャルアプリで使われるFlashを生成するための、FlashLite1向けコンパイラを開発したのでその概要について説明させていただきました。 FlashLite2/3向けのコンパイラはすでにありますが、FunctionやArrayが使えないなどと制約が多いFlashLite1向けのコンパイラをどのように作ったかが見所になっています。 このコンパイラのソースコードは後日公開予定です。乞うご期待! KLabセッション(2) 「システムモニタリングツール「Ganglia」の紹介」 KLabの2番手は私、横川がDSASで利用しているシステムモニタリングツール「Ganglia」に関してお話させていただきました。
yokogawa-k




負荷対策や、トラブル解決に必須となるシステムモニタリングツールとしてDSASではGnagliaを利用しています。 このGangliaの仕組みや、DSASでの活用事例などを紹介させていただきました。 ライブドアセッション(1) 「There is more than one way to cache it」 続きまして、ライブドアの長野さんからmemcachedの運用周りのことと長野さんが作成されているシステムモニタリングツール「CloudForecast」について解説いただきました。


CloudForecastは最近注目していたリソース監視ツールなので、仕組みや構成を作者から直接解説してもらえる素晴らしい機会に恵まれました。特に、ライブドア様の環境で5000リソース以上の情報を短時間で収集しているというCloudForecastの性能はほんとうに凄いと思います。 ライブドアセッション(2) 「DATAHOTEL P.O.I. での取り組み」 最後に、ライブドアの黒澤さんと冨成さんからソーシャル向けクラウドサービス「DATAHOTEL P.O.I. for Social」のサービス概要と、短納期を実現するためにシステム構築で工夫してることを解説いただきました。




サーバの追加をより迅速に行えるようにするため、初期セットアップではUSBブートやKickstartを活用されているというお話は、KLabでもいろいろと工夫しているところなので非常に共感させていただきました。 懇親会では、データセンターを運営しているライブドアさんならではの考え方やサービスなどをお聞きできて非常に面白かったです。 特にルーティングプロトコルまわりのお話(BGPとか!)などは、KLabの場合は利用しているデータセンターさんに全部お任せしてしまっていて考える機会もほとんどなく、ましてや触る機会もなど全くないので正直うらやましいお話でした。 お越しいただいたライブドアの皆様、本当にありがとうございました。 また機会がありましたら、ぜひよろしくお願いします。
 KLab若手エンジニアブログのフッター