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.
Als Product Name für die App verwenden wir EchoApp. Die anderen Einstellungen müssen nicht verändert werden.
Abschließend wird ein Projekt-Verzeichnis gewählt.
Nach dem Klick auf Create öffnet Xcode das neue Projekt.
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.
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:
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.
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.
Bei dem Button gehen wir ähnlich vor. Es wird wieder eine Linie vom UIButton
zum Controller gezogen.
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.
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.
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.