[5]:配列データを使って、UITableViewと連携させる

今回のチュートリアルは、配列データを使って、UITableViewと連携させる方法です。SQLやXMLのデータを表示させるための要素になるでしょう。

今回は「フルーツ」をテーマに、名称のほか、いくつかの追加情報をもつ「フルーツオブジェクトの配列」を作成します。UITabeleViewに各フルーツの名称を表示させ、名称がクリックされるとviewが遷移し、そのフルーツの詳細情報を表示させます。

今回の記事は以下の記事を既読の方を想定しています。

今回学ぶこと:

  • Navigation-Based Application の新規作成
  • フルーツClassのオブジェクト作成
  • NSArray 配列を作成し、書き込む
  • 新規ビューの追加
  • viewとコードを接続する
  • オブジェクトのデータをUITableViewに書き込む
  • viewを遷移させ、選択された行に基づくデータを表示させる


XCodeを起動し、Navigation-Based Application を使って、新規プロジェクトを作成します。Use Core Data..のチェックボックスはチェックしません。

プロジェクト名は「Fruit」とします。

05-1

アプリケーション内で使われるFruitオブジェクトを作成します。

XCode上から ファイル > 新規ファイル をクリックし、NSObject のサブクラスのオブジェクトを作成します。以下の図を参考にしてください。

05-2

新規サブクラスの名前は「Fruit.m」とします。同時に”Fruit.h”も作成がチェックされていることを確認して、完了します。

それでは、作成したFruitオブジェクトのプロパティを設定します。このアプリケーションの各フルーツは、名称と詳細情報を持っています。

Fruit.h を開き、以下のように編集します。

#import <Foundation/Foundation.h>

@interface Fruit : NSObject {

NSString *name;

NSString *description;

}

@property(nonatomic,copy) NSString *name;

@property(nonatomic,copy) NSString *description;

-(id)initWithName(NSString*)n description:(NSString *)desc;

@end

フルーツを表現するのに必要なプロパティを作成しました。

見慣れない一行がありますね。

-(id)initWithName(NSString*)n description:(NSString *)desc;

この行は関数を定義しています。この関数は、果物のオブジェクトを初期化するために呼び出されます。

すべてのNSobjectはinitメソッドを持っていますが、独自に設定したい時は、オブジェクトが作成される時に、名前や詳細情報を渡すことが出来ます。

Fruit.m を開き、以下のように編集してください。

#import “Fruit.h”

@implementation Fruit

@synthesize name,description;

-(id)initWithName:(NSString*)n description:(NSString*)desc {

self.name = n;

self.description = desc;

return self;

}

@end

ここでは、initWithNameメソッドを実装しています。このメソッドに渡される引数の名前と詳細情報をローカルコピーに設定しています。

ここで重要なのは、「return self」の行です。これは、コンストラクタとしてこのメソッドを使用するために非常に重要です。こうすることで、この関数が、新たに作成された果物オブジェクトのインスタンスを返すことができるようになります。(?)

次は、メインviewのタイトルの設定を行います。この設定はview間を移動し、戻るボタンを設置するためには、必ず指定しなければいけません。

RootViewController.m を開き、viewDidLoadメソッドを以下のように編集します。

#import “RootViewController.h”

#import “FruitAppDelegate.h”

#import “Fruit.h”

@implementation RootViewController

@synthesize fruitView;

#pragma mark –

#pragma mark View lifecycle

– (void)viewDidLoad {

[super viewDidLoad];

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.

// self.navigationItem.rightBarButtonItem = self.editButtonItem;

self.title = @”果物リスト;

}

これで、RootViewControllerオブジェクトのタイトルが「果物リスト」と設定されました。#import 文と @synthesize 文の追加を忘れないようにしてください。

次に、果物オブジェクトの配列を作成します。FruitAppDelegate.h を開き、以下のコードを追加します。

#import <UIKit/UIKit.h>

@interface FruitAppDelegate : NSObject <UIApplicationDelegate> {

UIWindow *window;

UINavigationController *navigationController;

NSMutableArray *fruits;

}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;

@property (nonatomic, retain) NSMutableArray *fruits;

@end

ここで加えているすべてが、NSMutableArrayのプロパティです。

NSArrayではなく、NSMutableArrayを使ったのは、後者の方がより柔軟ないくつかのメソッドを持っているからです。

FruitAppDelegate.m を開き、@synthesize 行を追加します。

これにより、他のオブジェクトは、果物の配列にアクセスできるようになります。また、Fruit.hのimport文を含めるようにしてください。

#import “FruitAppDelegate.h”

#import “RootViewController.h”

#import “Fruit.h”

@implementation FruitAppDelegate

@synthesize window;

@synthesize navigationController;

@synthesize fruits;

applicationDidFinishLaunching メソッドを以下のように編集します。

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

Fruit *apple = [[Fruit alloc] initWithName:@”りんご description:@”赤くて美味しい];

Fruit *orange = [[Fruit alloc] initWithName:@”オレンジ description:@”新鮮なオレンジジュースが出来ます];

Fruit *melon = [[Fruit alloc] initWithName:@”メロン description:@”大きくて、子供たちにも大人気];

self.fruits = [[NSMutableArray alloc] initWithObjects:apple,orange,melon,nil];

// Override point for customization after application launch.

// Add the navigation controller’s view to the window and display.

[window addSubview:navigationController.view];

[window makeKeyAndVisible];

return YES;

}

ここで記入したコードは、最初の Fruit から始まる三行でフルーツオブジェクトの新しいインスタンスを作成しています。init ではなく、initWithName を呼び出していることに注意してください。これによって、各フルーツの名称と詳細情報を追加しています。
その次の、
self.fruits = [[NSMutableArray alloc]initWithObjects:apple,orange,melon,nil];
先ほど作成したオブジェクトから配列を作成しています。最後の引数の nil が重要で、これを忘れると動作しません。

それでは、ユーザーがフルーツ名を選択した時に表示されるviewを作成していきましょう。プロジェクト内に表示されているxibファイルのいずれかを選択し、Interface Builder を起動します。

05-3メニューからFile > New.. をクリックします。

05-4iOS の中のview を選択し Chooseをクリックします。

そうすると空のviewが作成されます。そこに詳細情報を表示させるためのテキストフィールドを配置します。UITextFieldではなく、UITextViewを配置します。UITextViewは、マルチラインですので、複数行のテキストを表示するのに優れています。ライブラリからUITextViewを選択し、viewに配置してください。

05-5

上記の図の状態で保存してください。保存の際の注意点としては、現在作成中のプロジェクトの中に保存するということです。名前はFruitViewControllerとします。FruitプロジェクトにFruitViewController.xibを保存しますかというような確認画面が出るので、下の領域のFruitにチェックしてからAddボタンを押してください。

ここまで完了すれば、Interface Builderを閉じて、XCodeに戻りましょう。

viewを操作するにはViewControllerを作成する必要があります。

XCode上から ファイル > 新規ファイル を選択します。

UIViewController subclass を選択し、次へをクリックします。

FruitViewController.mという名前にして保存します。同時に”FruitViewController.h”も作成します。

それでは、先ほど追加したUITextViewInterface Builder Outlet を宣言します。

FruitViewController.h を開き以下のコードを追加します。

#import <UIKit/UIKit.h>

@interface FruitViewController : UIViewController {

IBOutlet UITextView *fruitDescription;

}

@property(nonatomic,retain) IBOutlet UITextView *fruitDescription;

@end

FruitViewController.m を開き、@implementation行の下に追加します。これで fruitDescription プロパティにゲッター&セッターメソッドを作成します。

@synthesize fruitDescription;

FruitViewController.xib をダブルクリックし、Interface Builderを起動します。先ほど作成したFruitViewControllerクラスとviewを関連づけます。

File’s Ownerオブジェクトをクリックしてください。

Identity Inspector から下図のように設定します。

05-7Interface Builder の最後の作業は、UITextViewを接続することです。

File’s Ownerオブジェクトを右クリックし、下図のようにviewウインドウ上のUITextViewとfruitDescriptionを接続します。

05-8同様にしてview をFruitViewController.xibとタイトル表示されているウインドウ内のviewを接続します。(下図参照)

05-9File’s OwnerオブジェクトのTools -> Connection Inspector が下図のようになっていれば成功です。

0510Interface Builderを閉じます。

次にやるべきことは、新しいview(フルーツがクリックされた時に遷移される画面)にプロパティを作成します。

RootViewController.h を開き、以下のように編集します。

#import <UIKit/UIKit.h>

#import “FruitViewController.h”

@interface RootViewController : UITableViewController {

FruitViewController *fruitView;

}

@property(nonatomic,retain)FruitViewController *fruitView;

@end

fruitViewController のプロパティを作成しました。#import 文が追加されていることにも注意してください。これにより、FruitViewController のインスタンスが作成可能になります。

次にRootViewController.m を開き、numberOfRowsInSection を探し、以下のように編集します。このメソッドは、UITableViewがいくつの行を表示するかを指定します。今回のケースでは配列の数だけ行を表示します。

// Customize the number of rows in the table view.

– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

FruitAppDelegate *appDelegate = (FruitAppDelegate *)[[UIApplication sharedApplication] delegate];

return appDelegate.fruits.count;

}

FruitAppDelegate から始まる行は、アプリケーションのappDelegateへのアクセスが出来るように設定しています。

デリゲートにアクセスすることで、fruitsのcountプロパティが返されます。(?)

The first line allows us to gain access to the appDelegate of our application. This is where we defined the fruit array. Once we have access to the delegate the count property of the fruit gets returned.

次に、cellForRowAtIndexPath を探し、以下のコードを追加します。

– (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];

}

FruitAppDelegate *appDelegate = (FruitAppDelegate *)[[UIApplication sharedApplication] delegate];

Fruit *f = (Fruit *) [appDelegate.f[ objectAtIndex:indexPath.row];

[cell.textLabel setText:f.name];

// Configure the cell.

return cell;

}

“FruitAppDelegate *appDelegate…”の行は、fruit array で宣言したappDelegateオブジェクトへのアクセスが出来るようにしています。その次の行は、フルーツ配列のobjectAtIndex メソッドを呼び出しています。

我々が使用するインデックスはindexPath.rowを介してアクセスすることができます。これはUITableViewの各行を表す整数値です。

最後にセルのsetTextメソッドを呼び、指定されたインデックスにある各フルーツオブジェクトの名称を表示します。

最後のステップです。

私たちはUITableView内のどの行が選択されたかを検出します。

didSelectRow を探し、以下のように編集してください。

– (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];

*/

FruitAppDelegate *appDelegate = (FruitAppDelegate *) [[UIApplication sharedApplication] delegate];

Fruit *fruit = (Fruit *)[appDelegate.fruits objectAtIndex:indexPath.row];

if(self.fruitView == nil){

FruitViewController *viewController = [[FruitViewController alloc] initWithNibName:@”FruitViewController” bundle:[NSBundle mainBundle]];

self.fruitView = viewController;

[viewController release];

}

[self.navigationController pushViewController:self.fruitView animated:YES];

self.fruitView.title = [fruit name];

[self.fruitView.fruitDescription setText:[fruit description]];

}

このメソッドは、ユーザーがUITableView上のセルをタップするたびに呼び出されます。indexPath パラメータは、ユーザーがクリックしたセル番号を表すrowというプロパティを持っています。

最初のラインはデリゲートへのアクセスを可能にしています。

次の行は、選択されたフルーツオブジェクトのコピーを作成するように設定しています。

The next line indexes into the fruits array and makes a copy of the selected fruit object.

ifで始まるセクションは、viewController が初期化されていなければ、初期化するように設定しています。

initWithNibName に渡す名前は、xibファイル名と一致していなければなりません。今回はFruitViewControllerです。

その次の行は、

Following this line is the line that pushes the viewController on to the navigationController stack. This causes the view to transition to the new view.

最後の2行は、新しいviewにフルーツの情報を渡しています。

まず、viewのタイトルにフルーツの名称を渡し、フルーツの詳細情報をdescriptionに設定しています。

以上で今回のチュートリアルは完了です。

以下の画像のように最初の画面では、フルーツリストが表示され、名称をクリックすれば、フルーツの詳細情報が表示され、タイトルがフルーツ名になったviewが表示されます。

05-11

↑起動直後の画面

05-12

↑メロンをクリックした後の画面

投稿日:
カテゴリー: 過去Blog

1件のコメント

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です