Cells(3)~サブクラスによるカスタマイズ

2010. 11. 07
本書ではサブビューを使ったCellsプロジェクトを改造していますが、(Apress社のサイト内のサンプルコードも別フォルダということもあり)ここでは既存のプロジェクトを別フォルダに移し、サブクラス用の同名のプロジェクトを新規に起こします。

912

見た目はほぼ同じですが、表示されるフォントが若干異なります。


●プロジェクトの作成

View-based Applicationテンプレートで、プロジェクト名を『Cells』とします。
(前回のコードを流用するので、前回のプロジェクトを退避させるか、別フォルダに作成してください)

903


●ビューコントローラのnibファイルの編集

nibファイルの編集は前回の『Cells(1)~サブビューによるカスタマイズ』の時と同じです。

画面全体にテーブルビューを貼り付けます。

CellsViewController.xibをダブルクリックしてInterface Builderで開き、LibraryウィンドウからViewウィンドウへTable Viewをドラッグ&ドロップします。

878

UITableViewオブジェクトはデータソースとデリゲートを持つ必要があります。

今回はデータソースもデリゲートもビューコントローラ(CellsViewController)で行うので、InspectorウィンドウのConnectionsタブを開き、『Outlets』の『dataSource』と『delegate』をDocumentウィンドウのFile's Ownerに接続します。

879

接続が完了したら保存してXcodeに戻ります。


●ビューコントローラのヘッダファイルの編集

CellsViewController.hを開き、デリゲート(UITableViewDelegate)とデータソース(UITableViewDataSource)プロトコルを導入し、データソースとなる配列witchesを宣言します。

配列や定数などの名前を変更していますが、コードの内容は同じです。
(太字が追加した部分)

#import <UIKit/UIKit.h>

@interface CellsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
    NSArray *witches;
}

@property (nonatomic, retain) NSArray *witches;

@end

913

今回は表示するラベルの特定をアウトレットで行うので、タグは不要です。

また、本書では行の高さを指定する定数を宣言していますが、変える理由も無いのでここでは省略します。


●ビューコントローラのソースファイルの編集

CellsViewController.mを開き、配列witchesとデータソースメソッドの実装を行います。
(太字が追加・変更した部分)

#import "CellsViewController.h"
#import "CustomCell.h"

@implementation CellsViewController

@synthesize witches;

/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
 
- (void)viewDidLoad {
    [super viewDidLoad];
    NSDictionary *row1 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Yoshika Miyafuji", 
    @"Name", @"A6M3a", @"Striker Unit", nil];
    NSDictionary *row2 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Mio Sakamoto", 
    @"Name", @"A6M3a", @"Striker Unit", nil];
    NSDictionary *row3 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Minna-Dietlinde Wilcke",
    @"Name", @"Bf109G-2", @"Striker Unit", nil];
    NSDictionary *row4 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Lynette Bishop", 
    @"Name", @"Spitfire Mk.IX", @"Striker Unit", nil];
    NSDictionary *row5 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Perrine-H.Clostermann",
    @"Name", @"VG39", @"Striker Unit", nil];
    NSDictionary *row6 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Erica Hartmann", 
    @"Name", @"Bf109G-6", @"Striker Unit", nil];
    NSDictionary *row7 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Gertrud Barkhorn", 
    @"Name", @"Fw190D-6", @"Striker Unit", nil];
    NSDictionary *row8 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Francesca Lucchini", 
    @"Name", @"G-55 Centauro", @"Striker Unit", nil];
    NSDictionary *row9 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Charlotte E Yeager", 
    @"Name", @"P-51D", @"Striker Unit", nil];
    NSDictionary *row10 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Eila Ilmatar Juutilainen",
    @"Name", @"Bf109G-2", @"Striker Unit", nil];
    NSDictionary *row11 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Sanya V.Litvyak", 
    @"Name", @"MiG60", @"Striker Unit", nil];
    NSArray *array = [[NSArray alloc]initWithObjects:row1, row2, row3, row4, row5, row6, row7, row8, row9, row10, row11, nil];
    self.witches = array;
    [row1 release];
    [row2 release];
    [row3 release];
    [row4 release];
    [row5 release];
    [row6 release];
    [row7 release];
    [row8 release];
    [row9 release];
    [row10 release];
    [row11 release];
    [array release];

}

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}


- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;

    self.witches = nil;
    [super viewDidUnload];
}

- (void)dealloc {
    [witches release];
    [super dealloc];
}

#pragma mark -
#pragma mark Table Data Source Methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.witches count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellTableIdentifier = @"CellTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellTableIdentifier];

    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }

    NSUInteger row = [indexPath row];
    NSDictionary *rowData = [self.witches objectAtIndex:row];
    cell.nameLabel.text = [rowData objectForKey:@"Name"];
    cell.unitLabel.text = [rowData objectForKey:@"Striker Unit"];
    return cell;
}

@end

914

shouldAutorotateToInterfaceOrientation:、メソッドはコメントアウトを解除しています。
(特に追記はしていません)

witchesプロパティの実装と、viewDidLoadviewDidUnloaddealloctableView:numberOfRowsInSection:メソッドの内容は前回と同じですのでコピペしてください。

つまり異なるのは、後述するサブクラス『CustomCell.h』のインポートの追加と、tableView:cellForRowAtIndexPath:メソッドの内容だけとなります。

・tableView:cellForRowAtIndexPath:

セル再利用時の識別子CellTableIdentifierを定義し、dequeueReusableCellWithIdentifier:メソッドで再利用可能なセルがあれば返す部分は前回と同じです。

if文でセル内容を新規作成する部分は、前回では各サブビューを座標指定してUILabelオブジェクトを作り、ラベルの属性を指定し、サブビューの生成を行っていました。

今回はこの部分を後述するサブクラスCustomCellとそのnibファイルCustomCell.xibで行いますので、nibファイルからカスタマイズされたセル情報を読み込む形になっています。

まずmainBundleメソッドでアプリケーションバンドルの位置を取得し、loadNibNamed:owner:options:メソッドでCustomCell.xibファイルを読み込みます。

loadNibNamed:owner:options:メソッドの挙動を理解しきれていないのですが、りぼんさんのサイト『テン*シー*シー/iPhoneアプリ開発、その(199) XIBを利用したカスタムUITableViewCell』によると、ownerの引数でselfを渡すと呼び出したクラス(この場合CellViewController)がFile's Ownerとなり、そのインスタンスに設定されるそうです。

option引数はよく分かりませんが、読み込んだnibファイルの一部を入れ替える場合に使用するものと思われ、ここではnilを設定しているのでそのまま読み込むことになります。

その後objectAtIndex:メソッドでテーブルセルを読み込むのですが、本書にあるように1を設定すると以下のようなエラーが出てアプリケーションが終了してしまいます。

 *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSMutableArray objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

これは配列の要素数より大きい値を指定した場合のエラーです。

ハナグロさんの『ちょっと、やったこと/思うこと/iPhoneアプリ作成:テーブルビューセルのサンプルアプリが落ちる』によると、iOS 2.1以降はFile's Ownerのエントリが含まれないために、セルを呼び出す場合は1から0に変更しなければならないようです。

各行固有の値は前回と同じで、インデックスパス(階層構造の配列に簡便にアクセスするためのパス)の行番号を取得し、objectAtIndex:メソッドでwitches配列から取得した当該行の内容をNSDictionaryのオブジェクトとして受け取ります。

その後、タグで値を個別に取得していた部分はアウトレットで特定しているので不要になり、サブクラスであるCustomCellのインスタンスであるcellにプロパティで設定しています。


loadNibNamed:owner:options:

- (NSArray *)loadNibNamed:(NSString *)name owner:(id)owner options:(NSDictionary *)options

レシーバのバンドルにあるnibファイルのコンテンツをアンアーカイブします。

戻り値はnibファイル内のトップレベルのオブジェクトを含む配列です。

配列はFile's Ownerへの参照またはプロキシオブジェクトを含んでおらず、nibファイルがアンアーカイブされた時にインスタンス化したオブジェクトのみを含みます。

手動でnibファイルオブジェクトが途中で解放されるのを防ぐために、オブジェクトまたは返される配列を保持しておく必要があります。

このメソッドを使ってユーザインターフェイスを読み込み、オブジェクトをコードに使用することができます。

このメソッドは読み込み処理中に各オブジェクトをアンアーカイブして初期化し、構成していた値をプロパティに設定し、他のオブジェクトへの接続を回復します。
(アウトレットの接続の確立には、アウトレット内のオブジェクトが自動的に保持するため、このメソッドはsetValue:forKeyメソッドを使用します)

nibの読み込み処理についての詳細は、『Resource Programming Guide』を参照してください。

File's Ownerのプロキシオブジェクトを超えるプロキシオブジェクトがnibファイルに含まれている場合、オプションで辞書を使用して、これらのプロキシのランタイム置換オブジェクトを指定することができます。

辞書では、UINibExternalObjectsキーを追加し、プロキシオブジェクト(キー)の名前を含む辞書の値を設定し、その場所にある実際のオブジェクトを使用します。

プロキシオブジェクトの名前は、Interface BuilderのInspectorウィンドウのIdentifierフィールドで割り当てられた文字列です。

name:nibファイルの名前で、拡張子『.nib』を含める必要はありません。

owner:nibのFile's Ownerオブジェクトとして割り当てられるオブジェクトです。

options:nibファイルを開く時に使うためのオプションを含む辞書を指定します。
この辞書で使用可能なキーのリストについては『Nib File Loading Options』を参照してください。


●サブクラスのコードファイルの作成

本書と話が前後していますが、セルのデザインをカスタマイズするUITableViewCellのサブクラスを作成します。

『グループとファイル』ペインの『Classes』フォルダを右クリックし、メニューから『追加』→『新規ファイル...』を選択します。

新規ファイルのテンプレートで左側の『iOS』カテゴリから『Cocoa Touch Class』を選択し、右上ペインで『Objective-C class』をクリック、右下ペインの『Subclass of』のメニューから『UITableViewCell』を選択し、ファイル名を『CustomCell』とします。

915


●サブクラスのヘッダファイルの編集

CustomCell.hを開き、アウトレットとなるUILabelのプロパティを宣言します。

固定文字列は単なるラベルなので、行毎に変化するnameLabelとunitLabelの2つのみになります。
(太字が追加した部分)

#import <UIKit/UIKit.h>

@interface CustomCell : UITableViewCell {
    UILabel *nameLabel;
    UILabel *unitLabel;

}

@property (nonatomic, retain) IBOutlet UILabel *nameLabel;
@property (nonatomic, retain) IBOutlet UILabel *unitLabel;


@end

916


●サブクラスのソースファイルの編集

CustomCell.mを開き、プロパティの実装と解放を行います。
(太字が追加した部分)

#import "CustomCell.h"

@implementation CustomCell

@synthesize nameLabel;
@synthesize unitLabel;


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
        // Initialization code
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (void)dealloc {
    [nameLabel release];
    [unitLabel release];

    [super dealloc];
}

@end

917


●サブクラスのnibファイルの追加

『グループとファイル』ペインの『Resources』フォルダを右クリックし、メニューから『追加』→『新規ファイル...』を選択します。

新規ファイルのテンプレートで左側の『iOS』カテゴリから『User Interface』を選択し、右上ペインで『Empty XIB』をクリック、ファイル名を『CustomCell』とします。

918

作成したCustomCell.xibをダブルクリックし、Interface Builderで開きます。

LibraryウィンドウからTable View CellをDocumentウィンドウにドラッグ&ドロップして追加します。

919

InspectorウィンドウでIdentityタブを開き、『Class Identity』の『Class』を『CustomCell』クラスに変更します。

920

本書ではこの後サイズ変更を行っていますが、その必要が見当たらないのでここでは変更しません。

DocumentウィンドウのCustom Cellをダブルクリックして開き、LibraryウィンドウからViewをCustom Cellウィンドウにドラッグ&ドロップし、InspectorウィンドウのSizeタブでX:0、Y:0、W:320、H:44に設定します。

このビューの上に、LibraryウィンドウからLabelをドラッグ&ドロップし、下表のように属性とサイズを設定します。

  AttributesSize
 LabelViewSize
 Text
Layout
(Alignment)
FontXYWH
Name:Name:右揃えHelvetica Bold, 12.0008021
Striker Unit:Striker Unit:右揃えHelvetica Bold, 12.00228021
nameLabel(Label)(左揃え)Helvetica, 18.090023021
unitLabel(Label)(左揃え)Helvetica, 18.0902223021

最後にDocumentウィンドウでCustom Cellを選択し、InspectorウィンドウのConnectionsタブを開き、アウトレットのnameLabelとunitLabelをそれぞれ接続します。

921

実行すると下図のようになります。

922



参考文献

テン*シー*シー/iPhoneアプリ開発、その(199) XIBを利用したカスタムUITableViewCell

ちょっと、やったこと/思うこと/iPhoneアプリ作成:テーブルビューセルのサンプルアプリが落ちる

NSBundle UIKit Additions Reference

はじめてのiPhone3プログラミングはじめてのiPhone3プログラミング
(2009/12/17)
Dave Mark、Jeff LaMarche 他

商品詳細を見る






bose_soundsport_free
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
09 | 2017/10 | 11
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 31 - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

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

Wish List
WACOM


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

bose_soundsport_free
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