Nav(18)~Detail Edit(3)

2011. 01. 17
●サブビューコントローラのヘッダファイルPresidentsViewController.hの編集

SecondLevelViewControllerクラスを継承し、テーブルに表示する配列のプロパティを宣言します。
(太字が追加・修正した部分)

#import <UIKit/UIKit.h>
#import "SecondLevelViewController.h"

@interface PresidentsViewController : SecondLevelViewController <UITableViewDelegate, UITableViewDataSource> {
    NSMutableArray *list;
}

@property (nonatomic, retain) NSMutableArray *list;

@end

1077

SecondLevelViewControllerを継承するため、ヘッダファイルSecondLevelViewController.hのインポートとクラス宣言でスーパークラスをUITableViewControllerからSecondLevelViewControllerへの変更を行います。

旧版の本書では@classでPresidentDetailControllerを指定していますが、このヘッダファイルではPresidentDetailControllerクラスのインスタンスを宣言していませんので、(サンプルコードのように)記述はしていません。

それとサンプルコードでは省略されていますが、テーブルを扱うので旧版の本書にあるようにUITableViewDelegateとUITableViewDataSourceプロトコルを採用します。

可変配列プロパティのlistは、サブビューでテーブルに表示する内容を定義します。


●サブビューコントローラのソースファイルPresidentsViewController.hの編集

ソースファイルでは、表示するテーブルの作成と、行をタップした際の処理を行います。
(太字が追加・修正した部分)

#import "PresidentsViewController.h"
#import "PresidentDetailController.h"
#import "President.h"


@implementation PresidentsViewController

@synthesize list;

#pragma mark -
#pragma mark Initialization

- (id)initWithStyle:(UITableViewStyle)style {
    // Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
    self = [super initWithStyle:style];
    if (self) {

        // Custom initialization.
    }
    return self;
}


#pragma mark -
#pragma mark View lifecycle

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"Presidents" ofType:@"plist"];

    NSData *data;
    NSKeyedUnarchiver *unarchiver;

    data = [[NSData alloc] initWithContentsOfFile:path];
    unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

    NSMutableArray *array = [unarchiver decodeObjectForKey:@"Presidents"];
    self.list = array;
    [unarchiver finishDecoding];

    [unarchiver release];
    [data release];
}
 

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


#pragma mark -
#pragma mark Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    return [list count];
}

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

    static NSString *PresidentListCellIdentifier = @"PresidentListCellIdentifier";

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

    // Configure the cell...
    NSUInteger row = [indexPath row];
    President *thePres = [self.list objectAtIndex:row];
    cell.textLabel.text = thePres.name;

    return cell;
}

#pragma mark -
#pragma mark Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Navigation logic may go here. Create and push another view controller.
    NSUInteger row = [indexPath row];
    President *prez = [self.list objectAtIndex:row];

    PresidentDetailController *childController = [[PresidentDetailController alloc] initWithStyle:UITableViewStyleGrouped];

    childController.title = prez.name;
    childController.president = prez;
 

    // Pass the selected object to the new view controller.
    [self.navigationController pushViewController:childController animated:YES];
    [childController release];

}

#pragma mark -
#pragma mark Memory management

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

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

- (void)viewDidUnload {
    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
    // For example: self.myOutlet = nil;

    self.list = nil;
}

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

@end

1078

1)PresidentDetailController.hとPresident.hのインポート

最初に行選択時に詳細ビューを表示するため、PresidentDetailControllerとPresidentクラスのヘッダファイルのインポートを行います。

旧版の本書では、詳細ビューをナビゲーションバーにプッシュするため、NavAppDelegate.hもインポートしていますが、ここではサンプルコードのようにnavigationControllerプロパティを使用するため不要になります。

2)プロパティlistの実装

可変配列のプロパティlistを実装します。

3)initWithStyle:の実装

旧版の本書では太字で示されていなく、サンプルコードでは省略されていますが、initWithStyle:メソッドのコメントアウトを解除してデフォルトのまま実装しています。

4)viewDidLoadの実装

viewDidLoadはコメントアウトを解除し、可変配列listを設定します。

最初にmainBundleメソッドでアプリケーションの場所を特定し、pathForResource:ofType:メソッドでアーカイブされているプロパティリストPresidents.plistのパスを取得します。

アーカイブされたプロパティリストはバイト列(バイナリデータ)なので、プロパティリストファイルからinitWithContentsOfFile:メソッドで取得したデータはNSDataのインスタンスdataで受け取ります。

次にバイト列であるdataからinitForReadingWithData:メソッドでデータをデコードし、初期化を行います。

初期化されたオブジェクトを格納しているNSKeyedUnarchiverのインスタンスunarchiverは、Presidents.plistの中身であるNSDictionaryのオブジェクトとなっています。

その辞書から、キーPresidents(Presidentクラスで定数としたキーPresidentとは別)でdecodeObjectForKey:メソッドによって取り出される配列arrayが、サブビューで表示するテーブルの内容(つまり歴代大統領の名前一覧)となっており、配列のプロパティlistに格納されます。

最後にfinishDecodingメソッドでデコードの完了を通知し、不要になったバイト列dataおよびプロパティリストをデコードしたオブジェクトunarchiverを解放します。

本書やサンプルコードではスーパークラスでの初期化を最後に行っていますが、ここでは最初に行っています。


initForReadingWithData:

- (id)initForReadingWithData:(NSData *)data

事前にNSKeyedArchiverによってエンコードされたアーカイブをデコードしレシーバを初期化します。

戻り値は、dataをデコード化して初期化したNSKeyedUnarchiverオブジェクトです。

データのデコード化が完了したら、finishDecodingを呼び出す必要があります。

dataが有効なアーカイブでない場合、このメソッドはNSInvalidArchiveOperationExceptionを発生させます。

dataNSKeyedArchiverによって事前にエンコードされたアーカイブを指定します。


finishDecoding

- (void)finishDecoding

オブジェクトのデコード化が完了したことをレシーバに伝えます。

このメソッドを呼び出すと、レシーバはデリゲートに通知し、アーカイブの最終的な操作を実行します。

このメソッドを一度呼び出すと、レシーバはそれ以降値のデコードをすることができません。

5)不要なView lifecycleのメソッド

viewWillAppear:、viewDidAppear:、viewWillDisappear:、viewDidDisappear:の4つは今回使用しないので削除します。

6)shouldAutorotateToInterfaceOrientation:の実装

本書やサンプルコードでは触れられていませんが、shouldAutorotateToInterfaceOrientation:のコメントアウトを解除してデフォルトの状態(ポートレートのみ有効)で実装しています。

7)numberOfSectionsInTableView:の削除

セクションが一つしか無いので、numberOfSectionsInTableView:は不要のため削除します。

8)tableView:numberOfRowsInSection:の実装

セクションの行数として、tableView:numberOfRowsInSection:ではサブビューの配列listの要素数をcountメソッドで返します。

9)tableView:cellForRowAtIndexPath:の実装

tableView:cellForRowAtIndexPath:では、サブビューDetail Editのテーブルセルの内容を設定します。

再利用識別子は『PresidentListCellIdentifier』と設定しています。

if文内のinitWithFrame:reuseIdentifier:メソッドはiOS 3.0以降非推奨なので、自動生成されるinitWithStyle:reuseIdentifier:で初期化しています。

セルの構成は、最初に引数のインデックスパスからrowプロパティで行番号をrowとして取得します。

次に配列listからrowの文字列をobjectAtIndex:メソッドで取得するのですが、受け取るインスタンスはPresidentクラスとなっています。

先のviewDidLoadメソッドでのインスタンス名を含めて照らし合わせると、プロパティリストPresidents.plistの構造は下記のようになっているようです。

Presidents.plist(アーカイブ化したプロパティリスト)
    |
    ∟Dictionary(NSKeyedUnarchiverのunarchiverの中身)
            |
            ∟Array(NSMutableArrayのarray、プロパティのlist)
                    |
                    ∟President(PresidentクラスのthePres)
                            |
                            ∟President(就任番号)
                            ∟Name(名前)
                            ∟FromYear(任期開始年)
                            ∟ToYear(任期終了年)
                            ∟Party(所属政党)

従って表示する指定行の名前は、PresidentクラスのインスタンスthePresからnameプロパティで取得します。

旧版の本書ではテキストの取得にtextプロパティを使用していますが、iOS 3.0以降は非推奨なので、代わりにtextLabeltextプロパティを使用しています。

なお新版のApress社のサイト内のサンプルコードでは名前とともに任期期間も表示するようになっていますが、それについては旧版の本書の内容を一通り説明してから行います。

10)不要なTable view data sourceメソッド

Table view data sourceのtableView:canEditRowAtIndexPath:tableView:commitEditingStyle:forRowAtIndexPath:tableView:moveRowAtIndexPath:toIndexPath:tableView:canMoveRowAtIndexPath:の4つは今回使用しないので削除します。

11)tableView:didSelectRowAtIndexPath:の実装

tableView:didSelectRowAtIndexPath:では、詳細ビューの表示(PresidentDetailControllerの呼び出し)を行っています。

まずインデックスパスからrowプロパティで行番号を取得し、配列listから選択行のPresidentクラスの要素prezをobjectAtIndex:メソッドで取得します。

次に詳細ビューPresidentDetailControllerのインスタンスを生成し、initWithStyle:でグループドテーブル(UITableViewStyleGrouped)として初期化します。

詳細ビューのタイトルは、選択行のPresidentクラスの要素prezからnameプロパティで名前を取り出し、titleプロパティで設定しています。

そして詳細ビューでの表示に必要な情報として、選択行のPresidentクラスの要素prezをpresidentプロパティに渡しています。

最後にnavigationControllerプロパティにpushViewController:animated:メソッドで詳細ビューchildControllerをプッシュし、詳細ビューへ移行します。

デリゲートへのchildControllerのプッシュはRootViewControllerのtableView:didSelectRowAtIndexPath:と同様に、navigationControllerプロパティを使って、childControllerをナビゲーションコントローラにpushViewController:animated:でプッシュしています。

12)viewDidUnloadの実装

本書やサンプルコードでは記述されていませんが、viewDidUnloadでプロパティlistの所有権放棄を行います。

13)deallocの実装

deallocでは本書やサンプルコードと同じく、プロパティlistの解放を行っています。


●詳細ビューコントローラのヘッダファイルPresidentsDetailController.hの編集

サブビューで選択された行に基づいて、テーブルに表示するラベルとテキストフィールドの配列や、テキストフィールドの内容を編集した際に使用する一時保管用の辞書と識別用のポインタのプロパティ、そしてナビゲーションバーのCancelやSaveボタン用のアクションメソッドなどを宣言します。
(太字が追加した部分)

#import <UIKit/UIKit.h>

@class President;

#define kNumberOfEditableRows 4
#define kNameRowIndex 0
#define kFromYearRowIndex 1
#define kToYearRowIndex 2
#define kPartyIndex 3
#define kLabelTag 4096


@interface PresidentDetailController : UITableViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate> {
    President *president;
    NSArray *fieldLabels;
    NSMutableDictionary *tempValues;
    UITextField *textFieldBeingEdited;

}

@property (nonatomic, retain) President *president;
@property (nonatomic, retain) NSArray *fieldLabels;
@property (nonatomic, retain) NSMutableDictionary *tempValues;
@property (nonatomic, retain) UITextField *textFieldBeingEdited;

- (IBAction)cancel:(id)sender;
- (IBAction)save:(id)sender;
- (IBAction)textFieldDone:(id)sender;


@end

1079

最初にPresidentクラスの宣言を行っています。

これは『Nav(5)~Disclosure Buttons(2)』でサブビューDisclosure Buttonsから詳細ビューを呼び出す際に行ったクラス宣言と同様に、Presidentクラスのインスタンスを宣言はするもののメソッドを呼び出すわけではないからです。

次に6つの定数を定義しています。

kNumberOfEditableRowsは詳細ビューのテーブル行数を示す物で、ここでは名前、任期開始年、任期終了年、所属政党を表示するため4としています。

kNameRowIndex、kFromYearRowIndex、kToYearRowIndex、kPartyIndexは詳細ビューのテーブルにおける各行のインデックス値を示しています。
 
kLabelTagはテーブルセルにおけるビューの識別用のタグです。

1083

詳細ビューの各テーブルセルは、左側に固定文字列のラベル(Name:やFrom:など)、右側に可変文字列のテキストフィールド(George Washingtonや1789など)で構成されています。

セル内にある複数のビューオブジェクト(ラベルとテキストフィールド)の内、ラベルを特定するためにkLabelTagは使用されます。

そしてサンプルコードでは省略されていますが、UITableViewDelegateUITableViewDataSourceプロトコル、さらに項目の編集にテキストフィールドを用いるのでUITextFieldDelegateプロトコルを採用します。

UITextFieldDelegateプロトコルは、テキストフィールドの編集が開始/終了した際のイベントに対応するメソッドで利用します。

Presidentクラスのpresidentは、サブビューDetail Editで選択された行に基づいて生成されて詳細ビューに受け渡されるインスタンスです。

配列fieldLabelsは、各セルの左側に表示するラベルを保持する配列です。

可変辞書tempValuesは、テキストフィールドの内容が変更された際に一時的に変更された値を保持するものです。

テキストフィールドのポインタtextFieldBeingEditedは、編集中のテキストフィールドを示すもので、編集中の内容を保存するために使用します。

アクションメソッドのcancel:とsave:は、ナビゲーションバーの各ボタンがタップされた時に呼び出されるメソッドです。

textFieldDone:メソッドは、テキストフィールドの編集時に出るキーボードのDoneボタンがタップされた時に呼び出されるメソッドです。



参考文献

NSKeyedUnarchiver Class Reference

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

商品詳細を見る






Bose QuietComfort 20
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
08 | 2017/09 | 10
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 QuietComfort 20
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