10.05.2012

Xcode 4, iPhone, Cocoa Touch, iOS4, iOS5

Tutorial: UITableViewController

In diesem Tutorial wird erklärt, wie mit einem UITableViewController eine einfach TableView erstellt. In dem Beispiel werden alle Font-Typen, die auf dem iPhone vorhanden sind, in der UITableView angezeigt.

Die folgende Abbildung zeigt die fertige iPhone-App, die alle Font-Typen in einer UITableView anzeigt.

Die folgende Abbildung zeigt die Architektur der fertigen App. Wie man sieht, wurde das Model-View-Controller-Pattern verwendet. Im Model werden die Font-Typen verwaltet und dem Controller bereitgestellt. Die View zeigt die Font-Typen an und benutzt für die Datenbeschaffung den Controller, d.h. die UITableViewDataSource und den UITableViewDelegate.

In folgenden Tutorial werden folgende Schritt durchgeführt:

  • Projekt anlegen
  • Model anlegen (FontModel)
  • Controller anlegen (ViewController)
  • View anlegen

Gestartet wird mit dem Anlegen einer iOS Application (⌘+⇧+N). In dem Fenster wählt man unter iOS den Eintrag Application aus. Als Template wird Empty Application selektiert.

Create New Project

Als Product Name für die App verwenden wir TableViewApp.

Create New Project

Abschließend wird ein Projekt-Verzeichnis gewählt.

Create New Project

Nach dem Klick auf Create öffnet Xcode das neue Projekt.

Create New Project

Nun wird das Model für die Font-Typen mit ⌘+N angelegt. In dem Fenster wählt man unter iOS den Eintrag Cocoa Touch aus. Als Template wird Objective-C class selektiert und mit Next bestätigt.

Create New Project

Als Namen für die Class wählt man FontModel und klickt auf Next.

Create New Project

Dann wird mit Create die Klasse erzeugt.

Create New Project

Das FontModel benötigt zwei Methoden. Eine zum Abfragen der Anzahl der verfügbaren Fonts und eine Methode, die den Namen eines Fonts für einen Index zurückliefert. Diese Methoden werden in der Datei FontModel.h definiert:

//
//  FontModel.h
//  TableViewApp
//
//  Created by Jörn Hameister on 10.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface FontModel : NSObject

-(int)countFonts;
-(NSString*)fontNameAtIndex:(int)index;

@end

Die Implementierung dazu sieht folgendermaßen aus:

//
//  FontModel.m
//  TableViewApp
//
//  Created by Jörn Hameister on 09.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import "FontModel.h"

@interface FontModel ()
    @property (nonatomic, strong) NSMutableArray* fontList;
@end

@implementation FontModel
@synthesize fontList = _fontList;

-(NSMutableArray*) fontList {
    if(_fontList == nil) {
        _fontList = [[NSMutableArray alloc] init];
    }
    return _fontList;
}

- (id)init {
    self = [super init];
    if(self) {
        NSArray *families = [UIFont familyNames];
        for(NSString * family in families) {
            NSArray *fonts =[UIFont fontNamesForFamilyName:family];
            for(NSString *font in fonts) {
                [self.fontList addObject:[font description]];
            }
        }
    }
    return self;
}

-(int)countFonts {
    return self.fontList.count;
}

-(NSString*)fontNameAtIndex:(int)index {
    return [self.fontList objectAtIndex:index];
}

@end

Als erstes wird ein NSMutableArray mit dem Namen fontList angelegt, in dem die Font-Namen abgelegt werden können. Im getter wird das NSArray einmal initialisiert. Die init-Methode sorgt dafür, daß das NSArray mit dem Font-Namen gefüllt wird. Dazu werden zuerst alle Font-Familien abgefragt und für jede Font-Familie, die Fonts bestimmt und deren Name in der fontList abgespeichert.

Die beiden Interface-Methoden, die vom Controller angesprochen werden, benutzen nun einfach die fontList um die Rückgabewerte zu bestimmen.

Nun wird ein der ViewController mit ⌘+N angelegt. In dem Fenster wählt man unter iOS den Eintrag Cocoa Touch aus. Als Template wird Objective-C class selektiert und mit Next bestätigt.

Create New Project

Als Namen für die Class wählt man ViewController und klickt auf Next.

Create New Project

Dann wird mit Create die Klasse erzeugt.

Create New Project

Die Datei ViewController.h wird so erweitert, daß sie von UITableViewController erbt und die DataSource UITableViewDataSource implementiert. Außerdem muß eine Variable für das FontModel anlelegt werden.

//
//  ViewController.h
//  TableViewApp
//
//  Created by Jörn Hameister on 10.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import <Foundation/Foundation.h>

@class FontModel;

@interface ViewController : UITableViewController<UITableViewDataSource>

@property (nonatomic, strong) FontModel *model;

@end

Zu der UITableViewDataSource ist anzumerken, daß die Deklaration in dieser Header-Datei auch weggelassen werden kann, weil sowohl DataSource als auch Delegate automatisch auf self gesetzt werden, wenn zu einem ViewController keine Xib-Datei existiert.

In der Datei ViewController.m wird nun die Variable model des FontModel im getter einmal initialisiert.

Als UITableViewDataSource muß die Klasse ViewController zumindest die Methoden tableView:numberOfRowsInSection: und tableView:cellForRowAtIndexPath: implementieren. Da in dem Beispiel keine sections verwendet werden, kann der Paramenter in der ersten Methode ignoriert werden und es muß nur die Anzahl der Fonts zurückgeliefert werden. In der zweiten Methode werden die UITableViewCells erstellt, d.h. es wird erst versucht eine Zelle aus einem "Zellenpool" mittels dequeueReusableCellWithIdentifier zu holen und erst bei Bedarf wird eine neue Zelle erzeugt. Dieses Vorgehen ist auf einem mobilen Device sinnvoll, da bei einer sehr großen Tabelle sonst der Speicherplatz nicht ausreichend wäre. Nachdem eine UITableViewCell verfügbar ist, wird der Font-Name im FontModel abgefragt und als Label-Text in der Zelle gesetzt.

//
//  ViewController.m
//  TableViewApp
//
//  Created by Jörn Hameister on 10.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import "ViewController.h"
#import "FontModel.h"

@implementation ViewController
@synthesize model = _model;


-(FontModel*)model {
    if (_model==nil) {
        _model = [[FontModel alloc]init];
    }
    return _model;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.model.countFonts;
}

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

    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
    if(!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
    }

    [[cell textLabel] setText:[self.model fontNameAtIndex:[indexPath row]]];
    return cell;
}
@end

Abschließend muß nur noch die Datei AppDelegate.m angepaßt werden, so daß der ViewController beim Starten der App als RootViewController verwendet wird. Dazu muß die Import-Anweisung ergänzt werden und die Methode application:didFinishLaunchingWithOptions: folgendermaßen angepaßt werden:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.


    ViewController* vc = [[ViewController alloc]init];
    [[self window]setRootViewController:vc];

    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

Nach dem Kompilieren und Starten mit ⌘+R öffnet sich der Simulator und zeigt die TableView mit allen Font-Typen an.