『iPhone SDKプログラミング大全』まとめ

2010. 05. 08
唐突ですが、2冊目として読み進めてきた『iPhone SDKプログラミング大全』については今回のまとめをもって終了します。

まだ残り100ページ余あるのですが、以降の内容はクラスの概要、プロパティやメソッドの紹介、当該部分のみのサンプルコードの一部というもので、これまでのような単体のアプリケーションという形での紹介をされていないため、私の実力的に内容を補完してご紹介するのは無理と判断しました。

残りは困った時にリファレンスとして使うことになると思います。

『iPhone SDKの教科書』まとめ』同様、本書と当サイトの記事の関係は以下の通りです。

第1章 iPhone SDKで開発を始める前に
1-1 iPhone SDKとは『iPhone SDKプログラミング大全』を始めてみた
1-2 iPhone OSとは
1-3 Xcodeとは
1-4 Interface Builder
第2章 Objective-C基礎講座
2-1 Objective-Cとはどんな言語か 
2-2 メソッドObjective-C言語のメモ書き(3)
2-3 クラスの宣言と実装
2-4 プロトコルObjective-C言語のメモ書き(4)
2-5 プロパティObjective-C言語のメモ書き(5)
2-6 高速列挙Objective-C言語のメモ書き(6)
2-7 オブジェクトの管理Objective-C言語のメモ書き(7)
第3章 プログラミングガイドシステム編
3-1 FoundationFoundationとCore Foundation(1)
FoundationとCore Foundation(2) 
3-2 Foundationが提供する機能FoundationとCore Foundation(3)
FoundationとCore Foundation(4)
バイト列
文字コードのエンコーディング
NSStringオブジェクトの書式
可変引数リスト
ロケールのリージョンコード
NSString(1)
NSString(2)
NSString(3)
NSString(4)
NSString(5)
CombiningとComposition
NSString(6)
NSString(7)
NSStringクラスメソッド一覧
Core Foundationのエンコーディング
Foundation(文字列)
Foundation(コレクション)
Foundation(日付と時間)
Foundation(数値)
Foundation(アーカイブ)
Foundation(ファイル管理)
Foundation(バンドル)
Foundation(初期設定)
Foundation(通知)
Foundation(タイマー)
3-3 サンドボックスサンドボックス
第4章 プログラミングガイドユーザインターフェイス編
4-1 ユーザインターフェイスUIKitの概要
アプリケーションのライフサイクル(1)
アプリケーションのライフサイクル(2)
アプリケーションのライフサイクル(3)
MVCアーキテクチャ
4-2 UI Kitを使ったアプリケーションターゲット/アクションモデル
チュートリアル:Hello World!
4-3 テーブルテーブル(1)
テーブル(2)
テーブル(3)
4-4 ナビゲーションバービューコントローラ
チュートリアル:ナビゲーションバーを使う
4-5 タッチイベント省略
4-6 加速度センサ
4-7 UI Kitが提供するそのほかの機能
第5章 プログラミングガイドネットワーク編
5-1 URLの読み込み省略
5-2 Core Location
5-3 Web Kit
第6章 プログラミングガイドメディア編
6-1 Cocoaグラフィックス省略
6-2 Core Graphics
6-3 アニメーション
6-4 OpenGL
6-5 オーディオ
6-6 ムービープレイヤ


●『iPhone SDKプログラミング大全』の総評

注:現在は既に改訂版として『iPhone SDK 3 プログラミング大全が出版されています。
以下の評価は旧版の『iPhone SDKプログラミング大全』に対してのもので、且つ新版は読んでいない状態ということを予めお断りしておきます。


手持ちの参考書の中で一番薄い(ページ数が少ない)という理由で2冊目に選びましたが、評価としてはかなり厳しいです。

冒頭から専門用語が多用されており、初心者には解説されている用語すら理解し難いと思います。

Mac OS Xのプログラマ、もしくはオブジェクト指向言語のプログラマを対象とした、『iPhoneプラットフォームの開発は初めて』という読者層向けな感じがします。

ですが、初心者向けに丁寧に解説している部分があったり、肝心な所の説明が一切無かったりと、内容がかなりちぐはぐな面が多々有ります。
(出版された時期的に、iPhone SDKが公開されたばかりで、まだ情報規制が厳しかった頃のものだからかもしれません)

特に後半になるとクラス概要とメソッドを軽く紹介するだけで、サンプルコードも不十分なので、日本初のiPhone SDK解説書をと焦って出したような感が有ります。

つまり、広く浅くテーマを拾ってはいますが内容が薄く、公式リファレンスや他の参考書を見ないと理解できず、少なくとも初心者向けではありません。
(かと言って中級者向けとしては内容が物足りない気がします)

所謂『その道のプロの技術屋が書いた解説書』の典型に陥っている本と言えます。

(初心者目線で)厳しいことを書いてきましたが、他の解説書では触れていない所の解説もされていたりするので買って損をするとは言いませんが、正直お薦めはいたしかねます。



参考文献

自作アプリをApp Storeで世界に向けて販売できる!! iPhone SDKプログラミング大全 (MacPeople Books)自作アプリをApp Storeで世界に向けて販売できる!! iPhone SDKプログラミング大全 (MacPeople Books)
(2009/01/06)
木下 誠

商品詳細を見る

iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)
(2009/09/08)
木下 誠

商品詳細を見る

チュートリアル:ナビゲーションバーを使う

2010. 05. 07
iPhone SDKプログラミング大全』の『チュートリアル:ナビゲーションバーを使う』ですが、例によってサンプルコードの事前説明が無いので、最終形態を説明します。
このサンプルは、ナビゲーションバーを利用した2段階層のテーブルを表示します。
(表示するだけで、編集などはできません)

255

256

ここで示すサンプルでは以下のような階層構造になります。

ナビゲーションコントローラ:NavBarAppDelegate
        |
        ∟THE IDOLM@STER SP(親ビューコントローラ:RootViewController)
                    |
                    ∟Wandering Star(子ビューコントローラ1)
                    |        ∟萩原雪歩
                    |        ∟水瀬伊織
                    |        ∟双海 亜美/真美
                    |        ∟四条 貴音
                    |
                    ∟Perfect Sun(子ビューコントローラ2)
                    |        ∟天海 春香
                    |        ∟菊地 真
                    |        ∟高槻 やよい
                    |        ∟我那覇 響
                    |
                    ∟Missing Moon(子ビューコントローラ3)
                             ∟如月 千早
                             ∟秋月 律子
                             ∟三浦 あずさ
                             ∟星井 美希

本来はビューコントローラが4つ必要になるのですが、本書の場合は1つファイルに親と子の2つのビューコントローラをまとめており、内部で条件分岐して表示しています(子ビューコントローラ1~3は条件分岐で1つのコントローラとし、親ビューコントローラのファイル内に含めている)ので、実用的なアプリケーションを組む際には注意しましょう。


●新規プロジェクトの作成

XcodeでNavigation-Based Applicationテンプレートを選択し、『NavBar』という名前の新規プロジェクトを作成します。

248

249

『Classes』下にある、『NavBarAppDelegate』がナビゲーションコントローラ、『RootViewController』がビューコントローラになります。


●NavBarAppDelegate.mの編集

本書では最後に編集していますが、話の流れとして自然になるように、ここでは最初にナビゲーションコントローラの説明を先にします。

NavBarAppDelegate.mでは、ビューコントローラ(RootViewController)を指揮下に置き、そのタイトルと親テーブルの配列(names。要素数3)を設定します。
(太字が追記した部分)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after app launch
    // RootViewControllerを取得
    RootViewController *rootViewController;
    rootViewController = (RootViewController *)navigationController.topViewController;


    // RootViewControllerを設定
    rootViewController.title = @"THE IDOLM@STER SP";
    rootViewController.names = [NSArray arrayWithObjects:@"Wandering Star", @"Perfect Sun", @"Missing Moon", nil];


    // ウィンドウの設定と表示を処理
    [window addSubview:[navigationController view]];
    [window makeKeyAndVisible];
    return YES;
}

254


・topViewController

@property(nonatomic, readonly, retain) UIViewController *topViewController

ナビゲーションスタック(ナビゲーションコントローラの管理する階層)最上位のビューコントローラを指します


●RootViewController.hの編集

ナビゲーションコントローラ(NavBarAppDelegate)下に置いた親ビューコントローラ(RootViewController)を編集します。

親テーブルのnames配列の宣言と、プロパティ宣言をします。
(太字が追記した部分)

@interface RootViewController : UITableViewController {
    NSArray *names;
}

@property (retain) NSArray *names;

@end

250


●RootViewController.mの編集

親ビューコントローラと子ビューコントローラを追加します。

本書の記載の仕方では編集箇所が分かり難いので、分割して説明します。
(スクリーンショットの行番号を参考にしてください)

まずヘッダファイルで宣言した、親テーブルのnames配列のプロパティを実装します。
(太字が追記した部分)

@implementation RootViewController

// プロパティを実装
@synthesize names;

251

続いて必須メソッドである、セクションの行数指定(tableView:numberOfRowsInSection:)とセル名指定(tableView:cellForRowAtIndexPath:)を実装します。
(太字が追記・編集した部分)

// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // namesの数を返す
    return [names count];

}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell.
    // セルの名前を設定
    cell.textLabel.text = [names objectAtIndex:indexPath.row];


    return cell;
}

252

最後に、親テーブルでセルを選択した後に子テーブルへ移動するメソッド(tableView:didSelectRowAtIndexPath:)と、子テーブルの配列(childNames。if分で条件分岐し、3つを共有しています)を実装します。
(太字が追記した部分)

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    /*
    <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
    // ...
    // Pass the selected object to the new view controller.
    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
    */

    // 名前を取得
    NSString *name;
    name = [names objectAtIndex:indexPath.row];

    // 子供となるコントローラに表示する内容を決定
    NSArray *childNames = nil;
    if ([name isEqualToString:@"Wandering Star"]) {
        childNames = [NSArray arrayWithObjects:@"萩原 雪歩", @"水瀬 伊織", @"双海 亜美/真美", @"四条 貴音", nil];
    }
    if ([name isEqualToString:@"Perfect Sun"]) {
        childNames = [NSArray arrayWithObjects:@"天海 春香", @"菊地 真", @"高槻 やよい", @"我那覇 響", nil];
    }
    if ([name isEqualToString:@"Missing Moon"]) {
        childNames = [NSArray arrayWithObjects:@"如月 千早", @"秋月 律子", @"三浦 あずさ", @"星井 美希", nil];
    }

    if (childNames) {
        // RootViewControllerをインスタンス化
        RootViewController *childViewController;
        childViewController = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil];
        [childViewController autorelease];

        // RootViewControllerを設定する
        childViewController.title = name;
        childViewController.names = childNames;

        // RootViewControllerをコントローラスタックに追加
        [self.navigationController pushViewController:childViewController animated:YES];
    }

}

253

親テーブルのnames配列で選択された行をname文字列とし、isEqualToString:メソッドで選択行の判別をしています。

判別後、子テーブルのchildName配列の内容を設定しています。

そして子テーブルのRootViewControllerのインスタンスを生成、コントローラスタックに追加します。

・tableView:didSelectRowAtIndexPath:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

現在選択した行のデリゲートを知らせます

このメソッドで、デリゲートは選択肢を処理します

選択した行を排他的にチェックマークの画像(UITableViewCellAccessoryCheckmark)を付けることもできます

このメソッドは、テーブルの編集プロパティがYESに設定されている(つまりテーブルビューが編集モードになっている)場合は呼び出しできません

詳細は『iOS Table Viewプログラミングガイド』の『第6章 選択の管理』を参照してください

tableView:新たに選択した行のデリゲートをテーブルビューオブジェクトに知らせます

indexPath:テーブルビューの新たに選択した行のインデックスパスを指定します


・initWithNibName:bundle:

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle

指定されたバンドルのnibファイルと新規に初期化されたビューコントローラ(UIViewControllerオブジェクト)を返します

このメソッドは、このクラスの指定イニシャライザです

nibNameパラメータにnilを指定し、カスタムサブクラスの中でloadViewメソッドをオーバーライドをしていない場合は、nibファイルの中からデフォルトのビューコントローラの名前(.nibなどの拡張子を除く)と適合するビューコントローラクラスの名前を探します

1つ見つかった場合、nibNameプロパティの値に適するクラス名か、このビューコントローラと関連するnibファイルと一致するどちらかになります

nibName:パス情報の無いnibファイル名を指定します
nibファイルを読み込んだ後にnibNameを設定したい場合、viewDidLoadメソッドをオーバーライドする必要があります
この引数がnilの場合、nibNameプロパティはnilに設定されます
この場合、ビュープロパティの設定でloadViewメソッドをオーバーライドする必要があります

nibBundle:nibファイルを検索するバンドルを指定します
このメソッドは、最初にバンドルの言語固有のプロジェクトディレクトリの中のnibファイルを探し、続いてリソースディレクトリを検索します
nilの場合、このメソッドはメインバンドル内のnibファイルを検索します


・pushViewController:animated:

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated

ビューコントローラをプッシュし(階層を掘って)、レシーバのスタックと表示を更新します

viewControllerパラメータ内のオブジェクトが、ナビゲーションスタックの一番上のビューコントローラになります

ビューコントローラをプッシュすると、表示しているビューの管理になります

animatedパラメータにより、ビューの表示が決定されます

animatedパラメータがYESの場合は、ビューがアニメーションで挿入され、そうでない場合は単純にビューが切り替わります

表示する前、ナビゲーションバーやツールバーがある場合は、ビューは自動的にサイズ調整して表示します

スタックの最上部に新しいビューコントローラと関連するビューを追加表示する場合、このメソッドはナビゲーションバーやツールバーも表示を更新します

iPhone OS 3.0以降では、新しいビューコントローラのツールバーアイテムが反映され、組み込みのナビゲーションツールバーの内容が更新されています
(『UINavigationController Class Reference/Updating the Navigation Bar』参照)

重要:iPhone OS 2.2以降では、viewControllerパラメータ内のオブジェクトが既にナビゲーションスタックにある場合、このメソッドは例外を発生します
(それ以前のバージョンのiPhone OSでは、何もしません)

viewController:スタックにプッシュするビューコントローラを指定します
このオブジェクトはタブバーコントローラのインスタンスや、既にスタックしているナビゲーションスタックを指定できません

animated:YESを指定した場合はアニメーションでビューを切り替え、NOの場合はアニメーションしません
ナビゲーションコントローラの起動時にNOを指定することもできます


●ビルドと実行

実行すると親テーブルが表示されます。

255

『Wandering Star』を選択した場合

256

『Perfect Sun』を選択した場合

257

『Missing Moon』を選択した場合

258



参考文献

iOS Table Viewプログラミングガイド

UINavigationController Class Reference

UITableViewDelegate Protocol Reference

UIViewController Class Reference

iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)
(2009/09/08)
木下 誠

商品詳細を見る

ビューコントローラ

2010. 05. 05
勉強のペースを上げるため、今後は英文和訳はできるだけ避ける方向で進めていきます。

サンプルコードで使っているクラスメソッドはできるだけ訳そうと思いますが、クラスの概要などの長文は(日本語の解説が見当たらない場合を除き)手間がかかる割に得るものが少ないので。
(誤訳の可能性が高く、ご覧になる方の危険性もありますので)

●ビューとビューコントローラ

iPhoneアプリケーションは、UIWindowクラスのインスタンスであるウィンドウを1つだけ持ちます。
このウィンドウは画面全体を覆っていて、その上に様々なビューを配置する土台となるものです。

ビューは実際に画面を描画したりユーザインターフェイスの部品を配置し、操作の応答を受けます。
ウィンドウと異なりビューは複数作ることができますが、そのビューの配置や切り替え、階層構造の制御を行うのがビューコントローラです。

247

iPodアプリケーションを例にすると、

・ステータスバー:キャリア名や3G/Wi-Fiの受信レベル、現在時刻、バッテリインジケータ
・ナビゲーションバー:前の階層へ戻るボタンや現在の階層名、次の階層へ進むボタン
・アプリケーションビュー:(ここではテーブルビュー)
・タブバー:プレイリストやアーティスト、曲などのビューを切り替えるボタン

という構成になっています。

ステータスバーはシステムによる別ウィンドウで、アプリケーションのウィンドウはステータスバーから下の領域全体となります。

ビューコントローラは、ナビゲーションバーとタブバーの間にあるアプリケーションビューを管理します。

アプリケーションビュー内の操作によるビューの管理はビューコントローラが担いますが、アプリケーションビューはナビゲーションバーやタブバーの操作の管理下にもあります。

ナビゲーションバーの操作によるビューの管理はナビゲーションコントローラ、タブバーの操作によるビューの管理はタブバーコントローラが行っています。

ナビゲーションコントローラやタブバーコントローラは特殊なビューコントローラです。

ただし、ナビゲーションコントローラとタブバーコントローラを組み合わせる場合は、タブバーが上位でナビゲーションが従属する形になります。

従って、コントローラの制御フローは以下のようになります。

タブバーコントローラ(UITabBarController)
        |
        ∟ナビゲーションコントローラ(UINavigationController)
        |            ∟ビューコントローラ(UIViewController)
        |
        ∟ビューコントローラ(UIViewController)※ナビゲーションコントローラを介さない場合


●UIViewControllerとそのサブクラス

UIViewControllerクラスはビューを管理する全てのコントローラのスーパークラスで、先日扱ったテーブルビューコントローラはもちろん、タブバーコントローラやナビゲーションコントローラも継承しています。

NSObject
    ∟UIResponder
    |        ∟UIApplication
    |        ∟UIView
    |                ∟UITabBar
    |                ∟UINavigationBar
    |
    ∟UINavigationItem
    |
    ∟UIBarItem
    |        ∟UIBarButtonItem
    |        ∟UITabBarItem
    |
    ∟UIViewController
            ∟UISplitViewController
            ∟UITabBarController
            ∟UITableViewController
            ∟UINavigationController
                    ∟UIImagePickerController
                    ∟UIVideoEditorController


●UINavigationController

UINavigationControllerはUIViewControllerのサブクラスで、そのインスタンスであるナビゲーションコントローラは、オブジェクトの階層を移動するナビゲーションインターフェイスを管理します。

ビューコントローラ1
        ∟ビューコントローラ2
                ∟ビューコントローラ3

ビューコントローラ1~3が上記のような階層構造になっている場合、ビューコントローラ1はビューコントローラ2の、ビューコントローラ2はビューコントローラ1のという表現をします。

ビューコントローラ2からビューコントローラ1に戻ることをポップ、ビューコントローラ1からビューコントローラ2に進むことをプッシュと言います。

ビューコントローラ2と3についても同様です。

また、コントローラの階層構造をコントローラスタックと呼びます。

プログラムでの実装形態は、実際には上記のような構造ではなく、ナビゲーションコントローラが各ビューコントローラを管理しています。

ナビゲーションコントローラ(UINavigationController。UINavigationBarをカプセル化して内包)
        |
        ∟ビューコントローラ1(UIViewController)
        |                ∟ビューオブジェクト1(UIView)
        |
        ∟ビューコントローラ2(UIViewController)
        |                ∟ビューオブジェクト2(UIView)
        |
        ∟ビューコントローラ3(UIViewController)
                        ∟ビューオブジェクト3(UIView)



参考文献

iOS View Controllerプログラミングガイド

iOSアプリケーションプログラミングガイド

iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)
(2009/09/08)
木下 誠

商品詳細を見る

テーブル(3)

2010. 05. 04
●チュートリアル:セクションを使ったテーブル

iPhone SDKプログラミング大全』の『チュートリアル:セクションを使ったテーブル』について説明します。

241

前回のテーブルに配列を1つ加え、セクションヘッダを設定し、2つのセクションに拡張します。


●TableAppDelegate.hの編集

追加するセクション用に配列を1つ増やします。
(太字が追記した部分)

@interface TableAppDelegate : NSObject <UIApplicationDelegate, UITableViewDataSource> {
    NSArray *names;
    NSArray *petitNames;
    UIWindow *window;
}

242


●TableAppDelegate.mの編集

追加するセクション用に配列の初期化、セクション数、セクションヘッダの設定をします。
(太字が追記した部分)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Override point for customization after application launch
    // namesを初期化
    names = [[NSArray arrayWithObjects:@"千早", @"やよい", @"貴音", nil] retain];

    // petitNamesを初期化
    petitNames = [[NSArray arrayWithObjects:@"ちひゃー", @"はるかさん", @"やよ", nil] retain];

    [window makeKeyAndVisible];
    return YES;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // セクションの数を返す
    // ここでは2つのセクションを表示
    return 2;
}


- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    // 第1セクションの場合
    if (section == 0) {
        // セクションのタイトルを『飼い主』にする
        return @"飼い主";
    }

    // 第2セクションの場合
    if (section == 1) {
        // セクションのタイトルを『ぷち』にする
        return @"ぷち";
    }

    return nil;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // 第1セクションの場合
    if (section == 0) {
        // namesの数を返す
        return [names count];
    }

    // 第2セクションの場合
    if (section == 1) {
        // petitNamesの数を返す
        return [petitNames count];
    }

    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // セルを作る
    UITableViewCell *cell;
    cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
        [cell autorelease];
    }

    // セルにテキストを設定
    // 第1セクションの場合
    if (indexPath.section == 0) {
        // namesから文字列を取得
        cell.textLabel.text = [names objectAtIndex:indexPath.row];
    }
    // 第2セクションの場合
    if (indexPath.section == 1) {
        // petitNamesから文字列を取得
        cell.textLabel.text = [petitNames objectAtIndex:indexPath.row];
    }
    return cell;
}

243


・numberOfSectionsInTableView:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

データソースにテーブルビューのセクション数を尋ね、返します
戻り値はtableViewのセクション数で、デフォルト値は1です

tableView:テーブルビューのオブジェクトを指定します


・tableView:titleForHeaderInSection:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

データソースに、指定したテーブルビューのセクションのヘッダタイトルを尋ね、返します

戻り値はセクションヘッダの戻り値になる文字列で、タイトルが無い場合はnilを返します

テーブルビューは、セクションヘッダタイトルに固定したフォントスタイルを使います
異なるフォントスタイルを使う場合は、デリゲートメソッドtableView:viewForHeaderInSection:の中で(UILabelオブジェクトなどの)カスタムビューを設定してください


●ビルドと実行

241

スクロールさせると、セクションヘッダの挙動が分かると思います。
(言葉では説明し難い表現なので、iPhone Simulatorなどで確認してください)

また、MainWindow.xib(本文のMainMenu.xibは間違い)でテーブルビューを選択し、Inspector WindowのAttributesでTable ViewのStyleを『Plain』から『Grouped』に変更すると、グループスタイルになります。

244

245

246

●NSIndexPathのUIKitへの拡張

前回触れるのを忘れていた、NSIndexPathの補足事項を説明します。

UITableViewオブジェクトの行とセクションを容易に識別するため、FoundationフレームワークのNSIndexPathクラスにはUIKitフレームワークのプログラミングインターフェイスを追加しています。

APIの構成は、クラスファクトリメソッドと2つのプロパティです。

indexPathForRow:inSection:メソッドは、セクションインデックス番号と行からNSIndexPathオブジェクトを生成します。

プロパティはそれらのオブジェクトから、行インデックス番号とセクションインデックス番号を返します。

・プロパティ

・行

テーブルビューのセクション内での行のインデックス番号を識別します(読み込み専用)

@property(readonly) NSUInteger row

・セクション

テーブルビュー内でのセクションのインデックス番号を識別します(読み込み専用)

@property(readonly) NSUInteger section



参考文献

UITableViewDataSource Protocol Reference

iOS Table Viewプログラミングガイド

NSIndexPath UIKit Additions

自作アプリをApp Storeで世界に向けて販売できる!! iPhone SDKプログラミング大全 (MacPeople Books)自作アプリをApp Storeで世界に向けて販売できる!! iPhone SDKプログラミング大全 (MacPeople Books)
(2009/01/06)
木下 誠

商品詳細を見る

テーブル(2)

2010. 05. 03
サンプルコードの説明に入る前に、TableViewに必要な2つのプロトコルについて、リファレンスの概要をお話しします。


●UITableViewDataSourceプロトコル

UITableViewDataSourceプロトコルは、アプリケーションのデータモデルをUITableViewオブジェクトとして取り扱うために採用します。

データソースは、テーブルビューを構築・変更するのに必要なテーブルビューオブジェクトの情報を提供します。

データモデルの典型的な役割は、テーブルビューの外観を構築する最小限の情報をデータソースから与えることです。

テーブルビューオブジェクトのデリゲートは、UITableViewDelegateプロトコルを採用したオブジェクトで、テーブルビューを構築する情報を提供します。

プロトコルの必要なメソッドは、テーブルビューを表示するのに必要な、UITableViewオブジェクトのセクション数とセクション毎の行数の情報を提供します。

データソースは実行するメソッドのオプションによって、色々なテーブルビューの外観の構成や、行の挿入、削除、並べ替えを行います。

注:テーブルビューでスワイプして削除できるようにする(デリートボタンを表示し、行を水平に横切って操作する)には、tableView:commitEditingStyle:forRowAtIndexPath:メソッドを実行する必要があります。

多くのメソッドはNSIndexPathオブジェクトを引数とします。

UITableViewは、NSIndexPathで表現された行インデックス(rowプロパティ)とセクションインデックス(セクションプロパティ)、そして指定した行インデックスとセクションインデックス(indexPathForRow:inSection:クラスメソッド)から組み立てたインデックスパスを宣言します。

(各インデックスパスの最初のインデックスは、セクションと次の行の識別をします)


●UITableViewDelegateプロトコル

UITableViewオブジェクトのデリゲートはUITableViewDelegateプロトコルを採用する必要があります。

プロトコルのオプションメソッドは、デリゲートによる選択の管理、セクションのヘッダとフッタの設計、セルの削除や並べ替えの補助などを行います。

多くのUITableViewDelegateメソッドは、NSIndexPathオブジェクトを引数または変数とします。

UITableViewは、NSIndexPathで表現された行インデックス(rowプロパティ)とセクションインデックス(セクションプロパティ)、そして指定した行インデックスとセクションインデックス(indexPathForRow:inSection:クラスメソッド)から組み立てたインデックスパスを宣言します。 

セクション内の行の位置は、通常行のインデックス番号を求める前に、セクションインデックス番号を求める必要があります。


●チュートリアル:テーブルを使ったアプリケーション

iPhone SDKプログラミング大全』の『チュートリアル:テーブルを使ったアプリケーション』について説明します。

本文では『チュートリアル形式で説明していく』とあるのはいいのですが、どういう物を作るのかという最終形態の説明も無く、そのままプロジェクトの作成から入るので先に説明します。

235

今回はプレーンスタイルのテーブルビューで、namesという一次配列をデータソースとしています。

セクションは1つ、ヘッダ/フッタ、インデックスなどが無いシンプルなものです。


●プロジェクトの作成

Window-based Applicationテンプレートで、『Table』というプロジェクト名で作成します。

236


●TableAppDelegate.hの編集

TableAppDelegate.hを開き、UITableViewDataSourceプロトコルとデータソースとなるnames配列の宣言を追加します。
(太字が追記した部分)

@interface TableAppDelegate : NSObject <UIApplicationDelegate, UITableViewDataSource> {
    NSArray *names;
    UIWindow *window;
}

237

本文中に説明がありませんが、『テーブル(1)』の『UITableViewの概要』で説明しているように、データソースは、UITableViewDataSourceプロトコルと、UITableViewDelegateプロトコルのデリゲートを採用している必要があります。

しかし、サンプルではUITableViewDataSourceプロトコルは追加していますが、UITableViewDelegateプロトコルを追加していません。

それでもコンパイルエラーが出ないのは、UITableViewDelegateプロトコルに必須メソッドが無く(UITableViewDataSourceプロトコルには必須メソッドがある)、セル選択時に応答する部分を実装していないからだと思われます。

まともにTableViewを実装する際には、UITableViewDelegateプロトコルの実装を忘れないようにしましょう。
(UITableViewDelegateプロトコルのメソッドを使おうとすれば、コンパイルエラーが出るとは思いますが・・・)


●ユーザインターフェイスのレイアウト

p.155の冒頭で『MainMenu.xibを開く』とありますが、MainWindow.xibの間違いです。

Table Viewオブジェクトを画面いっぱいに貼付けます。

238


●データソースの接続

貼付けたTable Viewオブジェクトを右クリックしてConnections Panelを開き、OutletsのdataSourceをDocument WindowのTable App Delegateに接続します。

239


●TableAppDelegate.mの編集

p.157でTestAppDelegate.mとありますが、TableAppDelegate.mの間違いです。

データソースとなるnames配列の初期化と、メソッドの追加を行います。
(太字が追記した部分)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch
    // namesを初期化
    names = [[NSArray arrayWithObjects:@"ゆきぽ", @"あふぅ", @"ちひゃー", nil] retain];

    [window makeKeyAndVisible];

    return YES;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // namesの数を返す
    return [names count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // セルを作る
    UITableViewCell *cell;
    cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewStyleDefault reuseIdentifier:@"UITableViewCell"];
        [cell autorelease];
    }

    // セルにテキストを設定
    cell.textLabel.text = [names objectAtIndex:indexPath.row];

    return cell;
}

アプリケーションのライフサイクル(2)』で説明しているように、現在はapplicationDidFinishLaunching:メソッドの代わりにapplication:didFinishLaunchingWithOptions:メソッドを使っています。

後述しますが、iPhone OS 3.0以降ではinitWithFrame:reuseIdentifier:メソッドの代わりにinitWithStyle:reuseIdentifier:を使うように推奨されていますので、入れ替えています。

また、サンプルコードをそのまま入力すると、最後の方の『セルにテキストを設定』のコードでコンパイルエラー('setText:' is deprecated)が出ます。

240

これは、『cell.text』の部分を『cell.textLabel.text』と修正すると治ります。
(iPhone OS 3.0で、textプロパティが廃止され、textLabelに置換されたためです)

さて『TableAppDelegate.hの編集』で、UITableViewDataSourceプロトコルには必須メソッドがあると説明しましたが、それがtableView:numberOfRowsInSection:とtableView:cellForRowAtIndexPath:です。

tableView:numberOfRowsInSection:は、テーブルビューを構成するのにあたって、そのセクションに何行あるかを指定します。

tableView:cellForRowAtIndexPath:は、セルの内容を構築します。


・tableView:numberOfRowsInSection:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

指定したテーブルビューのセクションの行番号を返します(必須)

tableView:構築するテーブルビューオブジェクトを指定します

section:tableView内のセクションのインデックス番号を指定します


・tableView:cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

指定したテーブルビューの特定の場所に挿入する、セルのデータソースを指定します(必須)

戻り値はUITableViewCellを継承したオブジェクトで、テーブルビューの行として使うことができます

(上手く訳せなかったので原文を載せます)An assertion is raised if you return nil.

戻り値のUITableViewCellオブジェクトは、パフォーマンス上の理由からアプリケーションでしばしば再利用されます

そのため、セルオブジェクトを構築する際に、予めテーブルビューにdequeueReusableCellWithIdentifier:メッセージを送り、再利用することを明示しておきます。

再利用可能なセルオブジェクトとなる識別子は、UITableViewCellのinitWithFrame:reuseIdentifier:メソッドを呼び出して、デリゲートがセルオブジェクトを初期化する時に割り当てます。

アクセサリビューや編集コントロールなど、テーブルセルの様々な属性は、セルのセパレータやデータソースの提供する情報に基づいて自動的に設定されます

tableView:セルのテーブルビューオブジェクトを指定します

indexPath:tableView内の行の位置のインデックスパスを指定します


・dequeueReusableCellWithIdentifier:

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier

識別子の位置で示された、再利用可能なテーブルビューのセルオブジェクトを返します

戻り値は、識別子で関連付けられたUITableViewCellオブジェクトで、再利用可能なセルオブジェクトが無い場合はnilを返します

パフォーマンス上の理由で、テーブルビューのデータソースは一般的にUITableViewCellオブジェクトを再利用するもので、tableView:cellForRowAtIndexPath:メソッドの中で行にセルを割り当てる時に指定します

テーブルビューは、UITableViewCellオブジェクトの列またはリストを保持し、テーブルビューのデリゲートは再利用のマークを維持します

(UITableViewCellのinitWithFrame:reuseIdentifier:メソッドで)生成時に再利用の識別子を割り当てることで、再利用のセルのマーキングを行います

データソースはdequeueReusableCellWithIdentifier:メソッドを実行し、この列内の特定の『テンプレート』セルオブジェクトにアクセスできます

セルの再利用識別子は、reuseIdentifierプロパティによってUITableViewCellを明示します

identifier:再利用可能なセルオブジェクトの、識別子の文字列を指定します
デフォルトの識別子はクラス名ですが、任意の値を設定することもできます


・initWithFrame:reuseIdentifier:

- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier

テーブルセルオブジェクトを初期化して返します
(iPhone OS 3.0では非推奨。代わりにinitWithStyle:reuseIdentifier:を使用してください)

戻り値は、初期化したUITableViewCellオブジェクト、またはオブジェクトが生成できなかった場合はnilを返します

このメソッドはクラスの指定する初期化メソッドです

再利用識別子はテーブルビューのセル(行)関連付けされ、一般的な構成と同じくセルの内容は含まれていません

tableView:cellForRowAtIndexPath:の実装の中で、テーブルビューのデリゲートはUITableViewメソッドのdequeueReusableCellWithIdentifier:メソッドを呼び出し、再利用識別子を渡して、セルオブジェクトを取得して現在の行の基礎として使います

frame:セルの枠の矩形を指定します
テーブルビューは自動的にセルの位置と最適なサイズを生成しますので、ほとんどの場合CGRectZeroを渡します
ただし、もし複数のサブビューを持つカスタムセルの場合、それぞれ独自に自動サイズ調整マスクを用いる時は、non-zero枠の矩形を指定すれば、テーブルビューはサブビューの位置とセルのサイズを自動的に調整します

reuseIdentifier:テーブルビューで複数の行を描く際に、セルオブジェクトを再利用するための識別子の文字列を指定します
再利用するセルオブジェクトが無い場合はnilを渡します


・initWithStyle:reuseIdentifier:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

スタイルと再利用識別子を指定してテーブルセルを初期化して返します

戻り値は、初期化したUITableViewCellオブジェクト、またはオブジェクトが生成できなかった場合はnilを返します

このメソッドはクラスの指定する初期化メソッドです

再利用識別子はテーブルビューのセル(行)関連付けされ、一般的な構成と同じくセルの内容は含まれていません

tableView:cellForRowAtIndexPath:の実装の中で、テーブルビューのデリゲートはUITableViewメソッドのdequeueReusableCellWithIdentifier:メソッドを呼び出し、再利用識別子を渡して、セルオブジェクトを取得して現在の行の基礎として使います

UITableViewCellのスタイルと異なる特徴を持つテーブルセルを構成する場合は、カスタムセルを作る必要があります

個々のセルの行の高さを設定したい場合は、デリゲートメソッドのtableView:heightForRowAtIndexPath:を実装してください

style:セルのスタイルの定数を指定します
(セルスタイルを参照してください)

reuseIdentifier:テーブルビューで複数の行を描く際に、セルオブジェクトを再利用するための識別子の文字列を指定します
再利用するセルオブジェクトが無い場合はnilを渡します
同じフォームの全てのセルには、同じ再利用識別子を使用してください


・セルスタイル(Cell Style)

セルのスタイルには4種類有り、UITableViewCell.hで定義されています。

全てのセルスタイルにおいて、テキストラベルの拡大はtextLabelプロパティ、縮小はdetailTextLabelプロパティによって利用できます。

typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
} UITableViewCellStyle;

・UITableViewCellStyleDefault

セルの単純なスタイルで、テキストラベル(左寄せ黒文字)とオプションで画像を表示できます。

・UITableViewCellStyleValue1

ラベルをセルの左側に左寄せ黒文字で、右側にサブラベルを小さな右寄せ青文字で表示します。
(環境設定アプリケーションで使われています)

・UITableViewCellStyleValue2

左端から少し離れた位置に、ラベルを右寄せ青文字で、サブラベルを小さな左寄せ黒文字で表示します。
(電話や連絡先アプリケーションで使われています)

・UITableViewCellStyleSubtitle

ラベルを左側に左寄せ黒文字で、その下にサブラベルを小さな灰色文字で表示します。
(iPodアプリケーションで使われています)

詳細は『iOS Table Viewプログラミングガイド』の『Table View Cellの標準スタイル』を参照してください


●ビルドと実行

結果は下図のようになります。

235

セルを選択することはできますが、特に応答するようなメソッドを記述していませんので、選択されているという表示になるだけです。



参考文献

UITableView Class Reference

UITableViewDataSource Protocol Reference

UITableViewDelegate Protocol Reference

UITableViewCell Class Reference

iOS Table Viewプログラミングガイド

iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)
(2009/09/08)
木下 誠

商品詳細を見る






bose_soundlink_revolve
Calendar
03 | 2017/04 | 05
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 - - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

bose_soundlink_revolve
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR