~☆~ 우하하!!~ 개발블로그

테이블뷰 사용하기 본문

iPhone & Cocoa

테이블뷰 사용하기

iwoohaha 2009. 7. 7. 23:47
반응형

Xcode 에서 Navigation-based Application 항목을 선택하여 프로젝트를 구성한 후 실행시키면 다음 그림과 같이 메인 뷰로 테이블뷰가 나타나게 된다.
Navigation-based Application 의 소스를 살펴보면 네비게이션 뷰 컨트롤러의 루트 뷰 컨트롤러는 UITableViewController 에서 파생된 뷰컨트롤러임을 알 수 있다.

@interface RootViewController : UITableViewController {
}

@end

이와 같이 간단하게 UITableViewController 를 사용하면 테이블뷰를 쉽게 나타나게 할 수 있다.

그렇다면 UITableViewController 가 아닌 UIViewController 에 테이블뷰를 얹기 위해서는 어떤 방법을 써야 할까.
지금부터 UIViewController 에 UITableView 를 얹는 과정을 살펴보자.

1. UIViewController 를 상속받는 뷰컨트롤러 클래스를 작성한다. 이 예제에서 UIViewController 클래스를 상속받는 뷰컨트롤러 클래스의 이름은 MainViewContrller 이다.
@interface MainViewController : UIViewController
{
}

@end

2. MainViewController 에 얹을 테이블뷰 멤버를 선언한다.
@interface MainViewController : UIViewController
{
    UITableView* tableViewItem;
}

@end

3. MainViewController 클래스의 구현파일(MainViewController.m)의 loadView 함수에 테이블뷰 생성 코드를 작성한다.
- (void)loadView
{
    tableViewItem = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    self.view = tableViewItem;
    [tableViewItem release];
}

이 상태에서 프로젝트를 빌드하여 실행시키면 다음과 같은 결과가 시뮬레이터에 나타나게 된다.
이 상태의  프로그램 실행 모습은 UITableViewController 를 직접 사용한 프로그램과 다르지 않다.
(어플리케이션 델리게이트 클래스의 applicationDidFinishLaunching 함수에는 다음과 같은 코드가 작성되어 있어야 한다.)
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    MainViewController* mainViewController = [[MainViewController alloc] init];
    navController = [[UINavigationController alloc] initWithRootViewController:mainViewController];
    [mainViewController release];
    [window addSubview:navController.view];
   
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}
그리고 어플리케이션 델리게이트 클래스의 멤버로 UINavigationController 클래스형 멤버를 추가해 둔 상태여야 한다.
@interface iPhoneAPIAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UINavigationController* navController;
}

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

@end

지금부터는 테이블뷰에 데이터를 출력하기 위한 추가 과정을 살펴보도록 한다.

테이블뷰에 데이터를 출력하기 위해서는 몇 가지 추가작업이 필수적이다.
테이블뷰에 나타낼 데이터멤버를 선언하고, 그 데이터멤버에 실제로 출력될 데이터를 추가해야 한다.
4. MainViewController 클래스의 멤버로 테이블뷰에 출력할 데이터를 저장할 수 있는 배열을 선언한다.
@interface MainViewController : UIViewController
{
    UITableView* tableViewItem;
    NSMutableArray* arrayItems;
}

@end

5. MainViewController 클래스의 loadView 함수에 이 배열에 데이터를 추가하는 루틴을 작성하도록 하자.
- (void)loadView
{
    tableViewItem = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    self.view = tableViewItem;
    [tableViewItem release];
   
    arrayItems = [[NSMutableArray alloc] initWithCapacity:0];
    for (int i = 0; i < 10; ++i)
    {
        [arrayItems addObject:[NSString stringWithFormat:@"item %d", (i+1)]];
    }
}

지금까지 테이블뷰에 나타낼 데이터를 작성하는 과정까지 완료되었다.
그렇다면 테이블뷰에 arrayItems 에 저장되어 있는 데이터를 과연 어떻게 출력시킬 수 있을것인가?
MVC 모델에 따르자면 테이블뷰는 V(View)에 해당되고, arrayItems 는 M(Model)에 해당된다고 할 수 있다. 그렇다면 M 을 V 에 출력될 수 있게 하는 C(Controller)는 무엇일까?
MainViewController 가 C 역할을 담당하게 된다.
테이블뷰의 경우 UITableViewDelegate, UITableViewDataSource 프로토콜을 사용하게 되므로 MainViewController 의 정의부분에 위 두 프로토콜을 추가한다.
6.
@interface MainViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
    UITableView* tableViewItem;
    NSMutableArray* arrayItems;
}

@end

이 상태에서 프로젝트를 빌드하게 되면 다음과 같은 경고가 발생하게 된다.
위 경고를 해석해보자면,
MainViewController 클래스의 구현이 완전하지 않다.
tableView:cellForRowAtIndexPath: 메소드와 tableView:numberOfRowsInSection: 메소드가 존재하지 않는다.
MainViewController 클래스에 UITableViewDataSource 프로토콜에 대한 구현이 완료되지 않았다.
이다.

이 중에서 메소드가 존재하지 않는다라는 경고는 UITableViewDelegate 프로토콜을 추가하고, 해당 프로토콜에 정의된 필수적인 메소드를 구현하지 않았기 때문에 발생한 것이다.
경고에 나타난 두 가지 필수적인 메소드의 원형은 다음과 같다.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
numberOfRowsInSection 메소드는 테이블뷰에 출력될 데이터의 개수를 구하기 위한 메소드이고, cellForRowAtIndexPath 메소드는 테이블뷰에 데이터를 출력하기 위한 UITableViewCell 을 만드는 작업의 메소드이다.

일단 다음 코드를 보고 위 두 메소드를 구현해보자.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [arrayItems 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] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
   
    // Configure the cell.
    cell.text = [NSString stringWithFormat:@"%@", [arrayItems objectAtIndex:[indexPath row]]];
   
    return cell;
}
numberOfRowsInSection 메소드에서 arrayItems 의 배열아이템 개수를 리턴하는 코드는 굳이 설명을 덧붙이지 않아도 이해될 것으로 본다.

문제는 cellForRowAtIndexPath 메소드 내용인데, 이 메소드가 리턴하는 오브젝트는 UITableViewCell 클래스형 오브젝트이다.
UITableViewCell 은 UITableView 의 항목을 구성하기 위한 클래스이다.

여기까지 작성한 상태에서 프로젝트를 빌드하여 실행시켜보자.

결과는 처음 실행때와 다를 바가 없다.
그 이유는 MVC 모델에서 C(Controller) 에 해당하는 코드만을 작성했을 뿐, 실제로 M, V 와 C 를 연결시켜주지 않았기 때문이다.
7. loadView 메소드에 다음 굵게 표시된 두 줄의 코드를 추가한다.
- (void)loadView
{
    tableViewItem = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    tableViewItem.delegate = self;
    tableViewItem.dataSource = self;
    self.view = tableViewItem;
    [tableViewItem release];
   
    arrayItems = [[NSMutableArray alloc] initWithCapacity:0];
    for (int i = 0; i < 10; ++i)
    {
        [arrayItems addObject:[NSString stringWithFormat:@"item %d", (i+1)]];
    }
}

이제 프로젝트를 빌드하고 실행시키면 비로소 테이블뷰에 항목들이 나타나게 된다.


반응형