28.04.2012

Xcode 4, iPhone, Cocoa Touch, iOS4, iOS5

Tutorial: iPhone Programmierung mit Cocoa Touch

In diesem Tutorial wird eine einfache iPhone-App erstellt. Diese ermöglicht es, eine Texteingabe über ein UITextField zu machen. Durch den Klick auf einen Button (UIButton) wird der Text in ein Label UILabel geschrieben. Die Anwendung dient hauptsächlich dazu, einen ersten Eindruck zu bekommen, wie man eine iPhone App erstellt und wie die einzelnen Komponenten verbunden werden. Dabei werden die drei UI-Element UILabel, UITextField und UIButton erklärt und es sollte deutlich werden, wie der Zusammenhang zwischen dem Model, der View und dem Controller (MVC) bei einer iPhone App ist. Die fertige App ist im folgenden Screenshot zu sehen:

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

Create New Project

Als Product Name für die App verwenden wir EchoApp. Die anderen Einstellungen müssen nicht verändert werden.

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

Anschließend wird links das Storyboard selektiert. Unter Editor wird der Assistent gewählt. Entweder mit der Tastenkombination ⌥⌘↩ und durch Klicken auf das mittlere Icon. Rechts daneben wird unter View das Icon Utilities, das rechte Icon der Gruppe, angeklickt oder mit dem Tastaturkürzel ⌥⌘0 ausgewählt. Ganz unten im Suchfeld der Object Library besteht die Möglichkeit nach Komponenten zu suchen.

Create New Project

Als nächstes werden die folgenden Komponenten der UIView hinzugefügt und angeordnet:

  • TextField (UITextField)
  • Button (UIButton)
  • Label (UILabel)

Dazu wählt man die Komponenten in der Object Library aus und zieht sie in die UIView und paßt jeweils die Größe an. Bei dem UILabel wird zusätzlich noch die Hintergrundfarbe geändert.

Danach sollte die View im Storyboard folgendermaßen aussehen:

Create New Project

Die Oberfläche ist soweit fertig. Was noch fehlt, sind die Verbindungen zwischen View und Controller. Diese legen wir an, indem das obere UITextField in der View selektiert und mit ctrl und gedrückter Mouse-Taste eine Linie in den Controller (ViewController.h) gezogen wird.

Create New Project

Nachdem wir den Mouse-Button loslassen, erscheint ein Dialog, in dem die Outlet-Verbindung zwischen View und Controller konfiguriert wird.

Connection ist mit dem Wert Outlet vorbelegt und muß nicht geändert werden. Als Object ist automatisch der ViewController eingetragen. Unter Name wird der Wert InputTextField angegeben. Als Type wird UITextField eingetragen. Außerdem kann der Storagetype gewählt werden. Da in unserer View immer ein strong-Pointer auf das UITextField existiert, kann in dem Dialog ein weak-Pointer verwendet werden.

Create New Project

Bei dem Button gehen wir ähnlich vor. Es wird wieder eine Linie vom UIButton zum Controller gezogen.

Create New Project

Diesmal wird allerdings eine IBAction mit dem Namen buttonPressed und dem Type id angelegt. Das Event ist Touch Up Inside und bei Arguments wird Sender ausgewählt.

Create New Project

Mit dem Label unter dem Button geht man genauso vor, wie mit dem UITextField weiter oben. Als Name wird OutputLabel verwendet.

Was jetzt noch fehlt, ist die eine Zeile Quellcode. Dazu öffnet man die Datei ViewController.m und ergänzt in der Methode buttonPressed:(id) sender folgendes:

- (IBAction)buttonPressed:(id)sender {
    OutputLabel.text = InputTextField.text;
}

Damit wird der Inhalt (der text) aus dem Eingabefeld InputTextField gelesen und dem Label OutputLabel als text zugewiesen.

Create New Project

Mit ⌘+R wird die App übersetzt und im Simulator gestartet. Nun kann im Textfeld eine Eingabe gemacht werden, die nach dem Klick auf den Button im Label unten angezeigt wird.

Prinzipiell funktioniert die App schon. Allerdings ist es so, daß das Modell noch fehlt. Bei so einer einfachen App braucht man es theoretisch nicht, allerdings ist es so, daß Apps verhältnismäßig schnell so kompliziert werden, daß die Daten nicht im Controller gehalten werden sollten. Man könnte sich auch vorstellen, daß der Text mit CoreData persistiert werden soll. Dann wäre ein Modell sinnvoll.

Die folgende Abbildung zeigt die Zusammenhänge zwischen Model-View-Controller.

Um ein einfaches Modell anzulegen, kann man folgendermaßen vorgehen. In dem Beispiel wird einfach eine neue Klasse EchoModel angelegt. Die Header-Datei sieht so aus:

//
//  EchoModel.h
//  EchoApp
//
//  Created by Jörn Hameister on 01.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface EchoModel : NSObject
@property (nonatomic, strong) NSString *echoText;
@end

Es wird ein NSString deklariert, der den Text speichert. In der Datei EchoModel.m muß nur das @synthesize eingefügt werden, damit getter und setter zur Verfügung stehen.

//
//  EchoModel.m
//  EchoApp
//
//  Created by Jörn Hameister on 01.05.12.
//  Copyright (c) 2012 http://www.hameister.org. All rights reserved.
//

#import "EchoModel.h"

@implementation EchoModel
@synthesize echoText;
@end

Damit das Modell im Controller verwendet werden kann, muß in der Datei ViewController.h ein @property ergänzt werden:

#import <UIKit/UIKit.h>

@class EchoModel;

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextField *InputTextField;
@property (weak, nonatomic) IBOutlet UILabel *OutputLabel;

- (IBAction)buttonPressed:(id)sender;
- (IBAction)doubleButtonPressed:(id)sender;


@property (nonatomic, strong) EchoModel* model;

@end

Die Datei ViewController.m wird folgendermaßen erweitert:

#import "ViewController.h"
#import "EchoModel.h"

@implementation ViewController
@synthesize InputTextField;
@synthesize OutputLabel;

@synthesize model = _model;

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

- (IBAction)buttonPressed:(id)sender {
    // Wert in das Modell schreiben
    self.model.echoText = InputTextField.text;
    
    // Wert aus dem Modell holen
    OutputLabel.text = self.model.echoText;
}
@end

Als erstes wird das @synthsize für model eingefügt und dann der Getter für model überschrieben. Grund dafür ist, daß das Modell erst erstellt werden soll, wenn es das erste mal benötigt wird (Lazy instantiation) um Speicher zu sparen.

In der Methode buttonPressed:(id)sender wird mittels Punkt-Notation self.model.echoText = InputTextField.text auf das Modell zugegriffen. (Es wäre auch möglich [self model] setEchoText:[InputTextField text]] zu schreiben.). Für das Setzen des Label-Texts wird ebenso verfahren.

Nach der Erweiterung und dem Übersetzen verhält sich die iPhone App genauso, wie die ursprüngliche Version ohne Modell.