4 Alles unter Kontrolle
»Liebe Mari, ich bin so froh', daß ich keine Rede nicht halten brauch', sondern das
Maul.«
– Ludwig Thoma
Im MVC-Muster nimmt die Controllerschicht eine zentrale Rolle ein. Sie haben im dritten Kapitel bereits mit zwei Klassen – dem App-Delegate und einem Viewcontroller – aus dieser Schicht intensiv gearbeitet. Dabei ist der Viewcontroller in diesem Projekt für die Steuerung und das Zusammenspiel der Views und der Nutzereingaben verantwortlich.
Übersichts- und Grundlagenkapitel
Dieses Kapitel stellt verschiedene Viewcontroller-Klassen des Systems vor und zeigt deren Anpassungsmöglichkeiten auf. Diese Viewcontroller sind wichtige Bausteine für alle iOS-Apps. Ein weiteres wichtiges Thema dieses Kapitels sind Storyboards und deren Unterschiede zu XIB- beziehungsweise NIB-Dateien. Der analoge Wecker dient dabei als Basis für Programmbeispiele für einen Teil der Projekte. Außerdem gibt es einige Programmbeispiele für die Themen, die sich nicht über das Weckerbeispiel sinnvoll abbilden lassen. Zu diesen Themen folgen in den nächsten Kapiteln allerdings noch größere Beispiele.
4.1 Viewcontroller, XIBs und Storyboards

Größere Apps stellen in der Regel mehrere Ansichten dar, und es wäre sehr unpraktisch, wenn deren Verwaltung über einen Viewcontroller erfolgen müsste. Stattdessen können und sollten Sie jeden Dialog auch über einen eigenen Viewcontroller verwalten. Die folgenden Abschnitte zeigen Ihnen, wie Sie die Erzeugung von Viewcontrollern in XIB-Dateien auslagern und XIB-basierte Projekte auf Storyboards umstellen können. Diese Aufgaben treten zwar in der Praxis eher selten auf; bei der Durchführung lernen Sie jedoch noch einige nützliche Details über die Architektur von Cocoa Touch-Apps kennen.
Erinnerung: XIB- und NIB-Dateien
Xcode wandelt bei der Erstellung einer Applikation alle XIB-Dateien in die wesentlich kompakteren NIB-Dateien um. Wir verwenden den Begriff XIB, wenn wir uns auf die Datei im Projekt beziehen. Die entsprechende Datei im Programm bezeichnen wir hingegen als NIB.
4.1.1 Erstellung von Viewcontrollern über XIB-Dateien

In den meisten Fällen erzeugen Sie Viewcontroller, indem Sie entweder ein neues Objekt über eine alloc-init-Kette anlegen oder sie aus einer NIB-Datei beziehungsweise einem Storyboard laden. Die erste Alternative sieht im Programmcode so aus:
AlarmClockViewController *theController =
[[AlarmClockViewController alloc]
initWithNibName:@"AlarmClockViewController"
bundle:nil];
Listing 4.1 Anlegen eines Viewcontroller-Objekts
Hier legen Sie die Klasse des neuen Objekts durch ihren Namen (vor alloc) fest. Außerdem übergeben Sie den Namen der NIB-Datei als Parameter an das neue Objekt. Dieses Objekt ist der Eigentümer oder auch File’s Owner der NIB-Datei.
Im Weckerprojekt finden Sie diese Zeile jedoch nur, wenn Sie Xcode 4.2 oder neuer für die Erstellung verwendet haben. Dort legt das Application-Delegate den initialen Viewcontroller oder auch Rootviewcontroller der App an. Die Applikation legt ihr Delegate über den Aufruf der Funktion UIApplicationMain an, die auch das Application-Singleton erzeugt und die Ereignisverarbeitung der Applikation startet. Damit sie das Delegate anlegt, muss diese Funktion den Klassennamen des Delegates als vierten Parameter erhalten. In der Wecker-App sieht der Aufruf beispielsweise so aus:
int main(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, 
NSStringFromClass([AlarmClockAppDelegate class]));
}
}
Listing 4.2 Applikationsstart des Weckers bei neueren Xcode-Versionen
Klassen und Klassennamen
Der Ausdruck für den Parameter für den Klassennamen des Application-Delegates sieht etwas umständlich aus. Anstatt NSStringFromClass([AlarmClockAppDelegate class]) könnten Sie ja auch kurz @"AlarmClockAppDelegate" schreiben. Die längere Notation hat hingegen zwei Vorteile: Zum einen ist sie eine Absicherung gegen Tippfehler, da der Compiler den Klassennamen überprüft; zum anderen erkennt Xcode diese Stelle als Verwendung der Klasse AlarmClockAppDelegate. Wenn Sie beispielsweise den Namen dieser Klasse über das Rename-Refactoring (siehe Kapitel 9, »Jahrmarkt der Nützlichkeiten«) ändern, ändert Xcode auch den Klassennamen an dieser Stelle, was Xcode bei einer Zeichenkettenkonstante nicht macht.
Ältere Xcode-Versionen legen den Rootviewcontroller über die Datei MainWindow.xib an. Diese Datei erzeugt neben dem initialen Viewcontroller auch das Application-Delegate und das Applikationsfenster mit der Klasse UIWindow. Sie haben mit dem Fenster in der Regel wenig zu tun, und seit iOS 5 kann auch das Application-Singleton das Fenster erzeugen. Es ist jedoch wichtig, da es die Verbindung zum Bildschirm des Geräts herstellt und alle angezeigten Views enthält. Sie können diese drei Objekte sehen, wenn Sie eine MainWindow.xib-Datei im Interface Builder öffnen (siehe Abbildung 4.1). Der Eigentümer dieser XIB-Datei ist übrigens das Application-Singleton.
Abbildung 4.1 Die drei Grundobjekte in der Datei »MainWindow.xib«
Bei solchen Projekten sollten Sie in der Funktion main nicht den Klassennamen des Delegates an die Funktion UIApplicationMain übergeben. Der Aufruf sieht hier so aus:
int main(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, nil));
}
}
Listing 4.3 Applikationsstart des Weckers mit »MainWindow.xib«
Natürlich hat Xcode beim Anlegen des Projekts auch dafür gesorgt, dass der Rootviewcontroller die richtige Klasse und XIB-Datei zugewiesen bekommt. Sie können das im Identitäts- und Attributinspektor überprüfen (siehe Abbildung 4.2 und Abbildung 4.3).
Abbildung 4.2 Festlegen der Viewcontroller-Klasse im Interface Builder
Bei der Auswahl der Klasse gelten hier dieselben Regeln, die Sie bereits für die Festlegung von Viewklassen kennengelernt haben. Deshalb enthält die Auswahlliste auch nur Unterklassen von UIViewController.
Abbildung 4.3 Auswahl der XIB-Datei im Attributinspektor
Die Controllererzeugung sowohl über den Programmcode als auch über die Serialisierung legt zunächst jedoch nur das Viewcontroller-Objekt an, ohne den View zu laden. Das geschieht erst, wenn der Viewcontroller ihn auch braucht – also in der Regel erst unmittelbar bevor er ihn anzeigt.
Anlegen neuer Viewcontroller in XIB-Dateien
Es ist natürlich sehr praktisch, wenn Xcode die Viewcontroller anlegt. In größeren Projekten mit mehreren Viewcontrollern müssen Sie das allerdings selbst machen. Dabei sollten Sie bei serialisierten Viewcontrollern immer auf folgende Dinge achten:
1. Sie sollten für den Viewcontroller ein Objekt anlegen. Es befindet sich in der Regel in der XIB-Datei des Viewcontrollers, der ihn anzeigt.
2. Diesem Viewcontroller sollten Sie eine weitere XIB-Datei über dessen Attributinspektor zuweisen.
3. Sie müssen die Klasse des Viewcontrollers im Identitätsinspektor dieses Objekts festlegen. Diese Angabe legt fest, welche Klasse der Viewcontroller hat.
4. Außerdem sollten Sie diese Klasse auch dem File’s Owner in der XIB-Datei des Viewcontrollers zuweisen. Das geht analog zu Schritt 3. Wenn Sie diesen Schritt nicht ausführen, ist das zwar kein Programmfehler. Der Interface Builder zeigt Ihnen jedoch nicht die Outlets und Actions an, die Sie in Ihrer Viewcontroller-Klasse deklariert haben.
Wenn Sie hingegen zuerst die Viewcontroller-Klasse über die Vorlage Objective-C Class anlegen, können Sie sich von Xcode auch die passende XIB-Datei anlegen lassen, in der auch der File’s Owner schon die Klasse des neuen Viewcontrollers besitzt. Dazu brauchen Sie nur das Häkchen With XIB for user interface so wie in Abbildung 4.4 zu setzen.
Abbildung 4.4 Anlegen eines Viewcontrollers mit XIB-Datei
4.1.2 Applikationsinitialisierung

Es gibt also drei Varianten von Apple, wie eine Applikation ihre Grundobjekte anlegt, und diese hängen von der verwendeten Xcode-Version und dem Projekttyp (XIB oder Storyboard) ab. In Tabelle 4.1 finden Sie eine Übersicht, durch welche Komponenten die einzelnen Grundobjekte in Abhängigkeit vom Projekttyp erzeugt werden.
| Objekt | XIB-Dateien | Storyboard | |
Xcode 4.2
|
Xcode 4.2
|
||
|
App-Delegate |
MainWindow.xib |
UIApplicationMain (siehe Listing 4.2) |
|
|
Rootview-controller |
Application-Delegate |
Storyboard |
|
|
Applikations-fenster |
Applikation |
||
Außerdem unterscheiden sich die Implementierungen der Delegate-Methode application:didFinishLaunchingWithOptions:. Während sie bei einer App mit Storyboard nur ein return YES; enthält, enthalten die XIB-basierten Varianten noch weitere Anweisungen. Wenn das Projekt eine MainWindow.xib-Datei enthält, muss die Delegate-Methode den Rootviewcontroller an das Fenster übergeben. Außerdem muss sie das Fenster anzeigen und in den Vordergrund bringen. Den entsprechenden Code finden Sie in Listing 4.4.
- (BOOL)application:(UIApplication *)inApplication
didFinishLaunchingWithOptions:(NSDictionary *)inOptions {
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Listing 4.4 Initialisierung des deserialisierten Fensters
Bei XIB-basierten Projekten ohne MainWindow.xib muss die Delegate-Methode das Fenster und den Rootviewcontroller erzeugen. Außerdem muss sie den Rootviewcontroller an das Fenster übergeben und dieses zur Anzeige bringen. Listing 4.5 enthält diese Schritte für eingeschaltetes ARC.
- (BOOL)application:(UIApplication *)inApplication
didFinishLaunchingWithOptions:(NSDictionary *)inOptions {
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc]
initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Listing 4.5 Erzeugung des Fensters und des Rootviewcontrollers
Bei universellen Apps müssen Sie beim Laden des Rootviewcontrollers eine Fallunterscheidung nach der Gerätekategorie machen, da iPads in der Regel angepasste XIB-Dateien erfordern. Die Gerätekategorie können Sie dabei über das Singleton UIDevice und dessen Property userInterfaceIdiom ermitteln. Sie liefert je nach Gerät einen der zwei möglichen Werte UIUserInterfaceIdiomPhone und UIUserInterfaceIdiomPad. In der Standardvorlage von Apple sieht damit die Unterscheidung dann so aus:
if([[UIDevice currentDevice] userInterfaceIdiom] ==
UIUserInterfaceIdiomPad]) {
self.viewController = [[ViewController alloc]
initWithNibName:@"ViewController-iPad" bundle:nil];
}
else {
self.viewController = [[ViewController alloc]
initWithNibName:@"ViewController" bundle:nil];
}
Listing 4.6 Den Rootviewcontroller abhängig von der Gerätekategorie laden
Projekte, die ihren Rootviewcontroller über das Application-Delegate laden, lassen sich relativ einfach umstellen, sodass die Applikationsinitialisierung über eine XIB-Datei erfolgt. Dazu legen Sie zuerst diese XIB-Datei an, indem Sie File • New • File... aufrufen und unter der Rubrik iOS • User Interface die Vorlage Application auswählen. Speichern Sie Datei unter dem Namen MainWindow in der Gruppe Supporting Files ab.
Do it yourself
Wenn Sie die Schritte für die Umstellung nachvollziehen wollen, legen Sie sich einfach mit Xcode 4.2 oder einer neueren Version ein Projekt aus der Vorlage Single View Application an. Achten Sie dabei darauf, den Schalter Use Storyboards im zweiten Schritt auszuschalten.
Die Umstellung auf eine Applikationsinitialisierung über eine XIB-Datei hat zwei Vorteile. Zum einen entfallen einige Zeilen Code in der Methode application:didFinishLaunchingWithOptions:.
Das ist bei einem einfachen Viewcontroller noch kein großer Vorteil. Wenn Sie allerdings einen Containerviewcontroller1 verwenden, ist dafür schon wesentlich mehr Programmcode nötig. Wenn Sie zum anderen eine iPhone-App später in eine universelle App umwandeln, erzeugt Xcode automatisch eine passende Datei für das iPad, und außerdem brauchen Sie auch keine Fallunterscheidung wie in Listing 4.6.
Abbildung 4.5 Anlegen von »MainWindow.xib«
Nach dem Speichern öffnet Xcode die Datei automatisch im Interface Builder. Als Nächstes öffnen Sie in dieser Datei den Identitätsinspektor des Objekts App Delegate und wählen dort unter Class die Klasse des Application-Delegates aus. Für den Rootviewcontroller ziehen Sie ein Viewcontroller-Objekt des gewünschten Typs aus der Bibliothek in die linke Seitenleiste des Interface Builders. Auch bei diesem Objekt stellen Sie gegebenenfalls die gewünschte Klasse über den Identitätsinspektor ein. Außerdem sollten Sie im Attributinspektor unter NIB Name den Namen der passenden XIB-Datei auswählen. [Containerviewcontroller werden in den Abschnitten Der Navigationcontroller bis Eigene Container- und Subviewcontroller genauer vorgestellt. http://hukd.mydealz.de/deals/nespresso-aeroccino-gratis-beim-kauf-von-250-kapseln-131582]
In der XIB-Datei fehlen jetzt noch die Verbindungen des Application-Delegates. Um sie einrichten zu können, müssen Sie zuerst dessen Propertys window und viewController als Outlets deklarieren. Dazu fügen Sie jeweils in der Klasendeklaration des Application-Delegates vor dem Klassennamen das Makro IBOutlet ein. Listing 4.7 enthält die hervorgehobenen Änderungen:
@property (strong, nonatomic) IBOutlet UIWindow *window;
@property (strong, nonatomic) IBOutlet
ViewController *viewController;
Listing 4.7 Umwandeln der Propertys in Outlets
Danach können Sie im Interface Builder den Verbindungsinspektor des Application-Delegates öffnen und die Outlets viewController und window mit den entsprechenden Objekten in der linken Leiste des Interface Builders verbinden (siehe Abbildung 4.6).
Abbildung 4.6 Verbindungen in »MainWindow.xib« ziehen
Sie haben jetzt zwar die vollständige MainWindow.xib-Datei angelegt, von der Ihr Programm allerdings noch nichts weiß. Das können Sie über Einstellungen im Target ändern, indem Sie im Projektnavigator das Projekt auswählen. Neben der Navigatorspalte zeigt Xcode eine Spalte mit dem Projekt und dessen Targets an. Wenn Sie das einzige vorhandene Target auswählen, können Sie dessen Einstellungen sehen. Die Einstellungen Main Storyboard und Main Interface legen das Haupt-Storyboard beziehungsweise die Haupt-XIB-Datei fest (siehe Abbildung 4.7). Um die App zur Verwendung der XIB-Datei zu bewegen, wählen Sie unter Main Interface den Eintrag MainWindow aus.
Abbildung 4.7 Applikationsinitialisierung über ein NIB
Jetzt brauchen Sie nur noch im Application-Delegate in der Methode application:didFinishLaunchingWithOptions: die beiden Zeilen für jeweils die Erzeugung und Zuweisung des Fensters und des Rootviewcontrollers zu entfernen, sodass der Code dem aus Listing 4.4 entspricht. Außerdem sollten Sie den vierten Parameterwert im Aufruf der Funktion UIApplicationMain in der Datei main.m durch nil ersetzen, sodass das Ergebnis Listing 4.3 entspricht. Durch diese Änderungen sollte die Applikation nun das Fenster, das Application-Delegate und den initialen Viewcontroller über die Datei MainWindow.xib erzeugen.
4.1.3 Storyboards

Apple hat Storyboards mit iOS 5 eingeführt, und Sie sollten bei Applikationen, die mindestens diese Betriebssystemversion voraussetzen, lieber Storyboards als XIB-Dateien einsetzen, da sie eine ganze Reihe von Vorteilen bieten. Dazu gehören neben den Übergängen auch statische Tableviews sowie Prototypen für Table- und Collectionviews.
Die Erzeugung von Viewcontrollern in Storyboards ähnelt der Erzeugung von Viewcontrollern in XIB-Dateien. Dieser Abschnitt zeigt Ihnen, wie Sie die Wecker-App von XIB-Dateien auf ein Storyboard umstellen. Dabei dient dieses Beispiel auch dazu, dass Sie die Funktionsweise sowohl von Storyboards als auch von XIB-Dateien besser verstehen können.
Projektinformation
Den Quellcode des nachfolgenden Beispielprojekts finden Sie auf der DVD unter Code/Apps/Storyboard/AlarmClock oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_2/Apps/Storyboard/AlarmClock.
Zur Vorbereitung legen Sie eine Kopie des Beispielprojekts AlarmClock an und öffnen diese Kopie in Xcode. Als Erstes legen Sie über File • New • New File... eine Storyboarddatei an, indem Sie unter der Rubrik iOS • User Interface die Vorlage Storyboard auswählen (siehe Abbildung 4.8). Der neuen Datei geben Sie den Namen AlarmClock. Ein Storyboard ersetzt alle XIB-Dateien für einen Gerätetyp und eine Lokalisierung. Sie erstellen zuerst das Storyboard für die englische iPhone-App und leiten später davon die iPad-Variante und lokalisierten Versionen ab.
Abbildung 4.8 Anlegen eines neuen Storyboards
Von den Grundobjekten müssen Sie nur den Viewcontroller im Storyboard anlegen und dessen View in das Storyboard kopieren. Wie Sie aus Tabelle 4.1 entnehmen können, erzeugt die Funktion UIApplicationMain das Application-Delegate, und die Applikation erzeugt das Applikationsfenster.
Storyboards und das Applikationsfenster
Wenn Sie ein Storyboard verwenden, muss das Application-Delegate die Property window implementieren. Die Applikation ruft den Getter dieser Property vor dem Aufruf der Methode application:didFinishLaunchingWithOptions: auf. Wenn er nil zurückliefert, erzeugt die Applikation ein Fenster und weist es über den Setter zu. Liefert die Property hingegen eine Referenz auf ein Fenster zurück, verwendet die Applikation dieses Objekt und legt kein neues an.
Als Erstes legen Sie den Viewcontroller an, indem Sie ein Viewcontroller-Objekt aus
der Bibliothek auf die Zeichenfläche ziehen. Danach öffnen Sie den Identitätsinspektor
des neuen Viewcontrollers und wählen AlarmClockViewController als Klasse des Objekts aus. Da Sie die Viewhierarchie aus der XIB-Datei übernehmen,
müssen Sie zuerst das Viewobjekt löschen, das Xcode beim Anlegen des Viewcontrollers
erstellt hat. Dazu klicken Sie einfach in den Viewcontroller auf der Zeichenfläche,
sodass er keinen blauen Rand hat, und drücken
oder
. Dadurch löschen Sie den View, und der Inhalt Ihres Storyboards sollte nun wie in
Abbildung 4.9 aussehen – der Viewcontroller in der linken Spalte hat keine Unterobjekte.
Kopieren will gelernt sein
Vielleicht wundern Sie sich, warum Sie nicht auch den Controller aus der XIB-Datei in das Storyboard kopieren sollen. Das ist zwar auch möglich, hat allerdings den unschönen Nebeneffekt, dass Xcode auch Eigenschaften mitkopiert, mit denen das Storyboard nichts anfangen kann. Dazu gehört beispielsweise der Name der XIB-Datei. Diese Einstellung führt im schlimmsten Fall zu einem Laufzeitfehler. Leider können Sie den Dateinamen im Storyboard nicht mehr löschen. Aus diesem Grund ist es besser, den Viewcontroller neu anzulegen.
Abbildung 4.9 Das Storyboard nach dem Einfügen des Viewcontrollers
Als Nächstes kopieren Sie den View aus der Datei AlarmClockViewController.xib in das Storyboard, indem Sie in der englischen XIB-Datei das oberste Viewobjekt auswählen
und
+
drücken. Wechseln Sie danach wieder in das Storyboard, und klicken Sie in den Viewcontroller
auf der Zeichenfläche, sodass er einen blauen Rahmen hat. Wenn Sie nun
+
drücken, fügt Xcode den View in den Controller ein. Ihr View sollte dann so wie in
Abbildung 4.10 aussehen.
Abbildung 4.10 Viewcontroller mit View im Storyboard
Die Outlet- und die Action-Verbindungen zwischen Viewcontroller und View müssen Sie neu anlegen. Tabelle 4.2 enthält zu den Views alle Verbindungen, die Sie anlegen müssen. Dabei entsprechen die Namen der Views in der ersten Spalte den Bezeichnungen in Abbildung 4.10.
| View | Outlet-Property | Action / Event |
|
Clock View |
clockView |
|
|
Clock Control |
clockControl |
updateAlarm / Touch Up Inside updateTimeLabel / Value Changed |
|
Switch |
alarmSwitch |
updateAlarm / Value Changed |
|
Label – Time |
timeLabel |
Außerdem sollten Sie den Longpress-Gesture-Recognizer im Clockview anlegen und dessen Selector mit der Methode updateAlarmHands: verbinden; das geht so wie in Kapitel 3, »Views und Viewcontroller«.
Damit haben Sie die Migration des Views in das Storyboard abgeschlossen. Allerdings verwendet die App das Storyboard noch nicht, weil ihre Einstellungen nach wie vor auf die XIB-Dateien verweisen. Sie können das überprüfen, indem Sie folgende Schritte ausführen:
- Löschen Sie die XIB-Dateien für die iPhone-Gerätefamilie aus dem Projekt. Dabei wählen Sie in der Alertbox den Button Move to Trash und nicht Remove References Only.
- Entfernen Sie die App vom Gerät beziehungsweise aus dem Simulator, indem Sie den Home-Button gedrückt halten, bis die Symbole zu wackeln anfangen. Durch Drücken der Löschmarke am Icon der App können Sie sie aus dem Simulator entfernen.
- Löschen Sie alle Zwischendateien des Projekts. Dazu öffnen Sie im Organizer (Window • Organizer oder
+
+
) den Reiter Projects. Wählen Sie das Projekt in der linken Spalte aus, und klicken Sie auf Delete in der Zeile Derived Data (siehe Abbildung 4.11).
Abbildung 4.11 Löschen der Zwischendateien über den Organizer
Wenn Sie danach die App erstellen und ausführen, zeigt Ihnen die Debuggerkonsole folgende Meldung an:
*** Terminating app due to uncaught exception 'NSInternalInconsistency- Exception', reason: 'Could not load NIB in bundle: 'NSBundle </Users/clemens/ Library/Application Support/iPhone Simulator/5.0/Applications/4BAF2833-C23D- 47EE-9F22-79B88D9E70A3/AlarmClock.app> (loaded)' with name 'MainWindow''
Die App versucht also nach wie vor, ihre Views über MainWindow.nib zu laden. Das können Sie über Einstellungen im Target ändern. Dazu öffnen Sie die Targeteinstellungen, indem Sie im Projektnavigator das Projekt auswählen. In der Spalte daneben zeigt Xcode das einzige Target, AlarmClock, des Projekts an. Wenn Sie es auswählen, können Sie dessen Einstellungen sehen. Die Einstellungen bei Main Storyboard und Main Interface legen das Haupt-Storyboard beziehungsweise die Haupt-XIB-Datei des Targets fest (siehe Abbildung 4.12). Um die App zur Verwendung des Storyboards zu bewegen, wählen Sie unter Main Storyboard den Eintrag AlarmClock aus.
Abbildung 4.12 Wechsel von XIB-Dateien zu einem Storyboard
Storyboards gibt es erst ab iOS 5
Das Wecker-Projekt läuft in der Version mit XIB-Dateien unter iOS 4 und neuer; Apple hat Storyboards hingegen erst mit iOS 5 eingeführt. Deshalb sollten Sie in der geänderten App diese Betriebssystemversion zwingend voraussetzen. Dazu ändern Sie einfach der Wert der Einstellung Deployment Target auf 5.0, was Sie ebenfalls über den in Abbildung 4.12 dargestellten Dialog machen können.
Mit diesen Änderungen haben Sie die Migration auf ein Storyboard abgeschlossen, falls die App keine Main-Interface-Datei (MainWindow.xib) verwendet.
Zusätzliche Schritte bei MainWindow.xib
Falls Ihre App das Fenster, das Application-Delegate und den initialen Viewcontroller allerdings über die Datei MainWindow.xib erzeugt, sind noch einige zusätzliche Änderungen notwendig. Nach den Änderungen zeigt die Debuggerkonsole in diesem Fall nämlich zwei Fehlermeldungen an:
The app delegate must implement the window property if it wants to use a
main storyboard file.
Applications are expected to have a root view controller at the end of
application launch
Die erste Meldung macht scheinbar keinen Sinn, da das Application-Delegate ja die Property window implementiert; allerdings kennt das modifizierte Programm jetzt nicht mehr das Delegate. Die Version mit XIB-Dateien hat ja das Application-Delegate über die Datei MainWindow.xib angelegt und mit dem Application-Singleton verbunden. Da Sie das Delegate indes nicht über das Storyboard anlegen können, müssen Sie das über den Programmcode machen. Öffnen Sie dazu die Datei main.m, und ändern Sie deren Inhalt entsprechend Listing 4.8 ab. Die wesentliche Änderung [Um Wiederholungen zu vermeiden, haben wir auf eine detaillierte Darstellung der nachfolgenden Schritte verzichtet.] in dem neuen Code ist die Verwendung des vierten Parameters der Funktion UIApplicationMain. Über diesen Wert können Sie den Namen der Klasse des App-Delegates festlegen. Cocoa Touch erzeugt aus Iihm die Klasse und daraus wiederum das App-Delegate. Das Application-Singleton bekommt dieses Objekt dann als Delegate zugewiesen.
#import <UIKit/UIKit.h>
#import "AlarmClockAppDelegate.h"
int main(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil,
NSStringFromClass([AlarmClockAppDelegate class]));
}
}
Listing 4.8 Erzeugung des App-Delegates über Programmcode
Bleibt noch die zweite Meldung übrig. Bei der Verwendung von XIB-Dateien haben Sie dem Fenster den Wurzelviewcontroller über die Property rootViewController explizit zugewiesen. Bei Storyboards geschieht diese Zuweisung implizit, indem Sie bei einem Viewcontroller im Storyboard die Eigenschaft Is Initial View Controller im Attributinspektor setzen. Sie erkennen diesen Viewcontroller an einem grauen Pfeil ohne Ursprungsobjekt, der auf den Viewcontroller zeigt (siehe beispielsweise Abbildung 4.9).
Da das geänderte Projekt die Property viewController im Application-Delegate nicht mehr braucht, sollten Sie sie aus der Header- und der Implementierungsdatei entfernen. Das betrifft nicht nur die Deklaration und die @synthesize-Anweisung, sondern auch alle Anweisungen in den Methoden dealloc und application:didFinishLaunchingWithOptions:, die auf diese Property zugreifen. Außerdem können Sie den Aufruf der Methode makeKeyAndVisible entfernen, da Cocoa Touch auch diese Aufgabe wegen der Verwendung des Storyboards für Sie übernimmt. Den geänderten Code der Datei AlarmClockAppDelegate.m können Sie Listing 4.9 entnehmen.
@implementation AlarmClockAppDelegate
@synthesize window;
@synthesize soundId;
#pragma mark -
#pragma mark Application lifecycle
- (void)dealloc {
self.soundId = nil;
self.window = nil;
[super dealloc];
}
- (BOOL)application:(UIApplication *)inApplication
didFinishLaunchingWithOptions:(NSDictionary *)inOptions {
return YES;
}
Listing 4.9 Geänderte Methoden im App-Delegate
Nach diesen Änderungen sollte die App im iPhone 5.0 Simulator und auf einem iPhone mit iOS 5 wieder funktionieren.
Lokalisierung und Anpassung an das iPad
Über den Dateiinspektor des Storyboards können Sie nun lokalisierte Versionen des Storyboards anlegen. Dabei können Sie wie in Kapitel 3 vorgehen. Auf dem iPad läuft die App auch, sie stellt allerdings dort das Ziffernblatt verzerrt dar. Anscheinend verwendet also das iPad das Storyboard der iPhone-Version. Um diesen Darstellungsfehler zu beheben, müssen Sie ein eigenes Storyboard für das iPad anlegen. [Um Wiederholungen zu vermeiden, haben wir auf eine detaillierte Darstellung der nachfolgenden Schritte verzichtet.] Die Datei erzeugen Sie wieder über den Menüpunkt File • New • New File... und die Vorlage Storyboard. Achten Sie darauf, iPad als Gerätefamilie auszuwählen. Nennen Sie die neue Datei AlarmClock-iPad, und legen Sie sie in der Gruppe iPad in Ihrem Projekt ab.
Um den Viewcontroller in dem neuen Storyboard anzulegen, können Sie entweder die ganzen Schritte vom Anfang dieses Kapitels noch einmal mit der Datei AlarmClockViewController-iPad.xib durchlaufen. Alternativ können Sie jedoch auch den Viewcontroller aus dem iPhone-Storyboard in das iPad-Storyboard kopieren und den View entsprechend anpassen. Das Ziffernblatt sollte dabei eine quadratische Fläche (768 × 768 Pixel) bekommen, um eine schöne Darstellung zu erhalten. Auch das iPad-Storyboard sollten Sie lokalisieren.
Damit die App auf dem iPad auch das entsprechende Storyboard verwendet, öffnen Sie wieder die Target-Einstellungen und scrollen die Ansicht nach unten, bis Sie den Bereich iPad Deployment Info sehen. Auch dort finden Sie zwei Einstellungen: Main Storyboard und Main Interface. Wählen Sie hier unter Main Storyboard den Wert AlarmClock-iPad aus.
Nach der Erstellung des Storyboards können Sie alle XIB-Dateien für das iPad aus dem Projekt löschen. Zur Sicherheit sollten Sie auch noch mal alle Zwischendateien löschen und die App von den Geräten und aus den Simulatoren löschen.
Epilog
Die Umstellung von XIB-Dateien auf Storyboards ist schon für so ein kleines Projekt wie den analogen Wecker recht aufwendig. Glücklicherweise müssen Sie das allerdings in der Praxis so gut wie nie durchführen, da ja nichts gegen eine Weiterverwendung von XIB-Dateien spricht.
In den Storyboards haben Sie keinen direkten Zugriff mehr auf das Application-Delegate. Sie sollten sich also angewöhnen, Outlets und Actions immer in dem Viewcontroller anzulegen, der den entsprechenden View verwaltet. Das vereinfacht Ihnen gegebenenfalls eine spätere Umstellung auf ein Storyboard.
Das Beispielprojekt AlarmClock im Ordner Storyboard auf der beiliegenden DVD verwendet außerdem automatisches statt manuelles Referenzenzählen. Diese Umstellung können Sie mit dem in Kapitel 2 beschriebenen Menüpunkt Edit • Re-factor • Convert to Objective-C ARC... durchführen. Das Projekt verfügt außerdem noch über ein paar neue Eigenschaften, um die Möglichkeiten von Storyboards zu demonstrieren; dazu jedoch später mehr.
4.1.4 Modale Dialoge

Wenn Ihre App mehrere Viewhierarchien verwalten soll, müssen Sie auch die Möglichkeit haben, dazwischen zu wechseln. In Kapitel 3, »Views und Viewcontroller«, haben Sie im Zusammenhang mit Übergängen bereits eine Möglichkeit dafür kennengelernt. Ein Übergang führt den View-Wechsel allerdings nicht durch, sondern stößt ihn nur an. Apple hat Übergänge mit Storyboards und iOS 5 eingeführt. Auf älteren Betriebssystemversionen können Sie sie also nicht verwenden. Dieser und die folgenden Abschnitte beschreiben, wie Sie Views aus dem Programmcode heraus anzeigen können; Abschnitt 4.1.6 geht dabei auch noch mal genauer auf Übergänge ein.
Modal versus nichtmodal
Ein modaler Dialog sperrt alle anderen Eingabemöglichkeiten einer Applikation. Der Nutzer muss zuerst diesen Dialog bearbeiten, bevor er mit der Applikation weiterarbeiten kann. Typische modale Dialoge unter OS X sind die Dateiauswahlboxen. Ein Beispiel für nichtmodale Dialoge unter OS X sind die Dateiinformationsfenster des Finders.
Auf dem iPhone sperrt ein modaler Dialog alle anderen Eingaben des Viewcontrollers, der ihn anzeigt, indem er ihn komplett verdeckt. Das geht auch auf dem iPad; allerdings muss er dort nicht den ganzen Bildschirm bedecken.
Die Klasse UIViewController besitzt für die Anzeige modaler Dialoge die Methode presentViewController:animated:completion:, die Apple mit iOS 5 eingeführt hat. Über diese Methode können Sie einen Viewcontroller über dem Viewcontroller darstellen, dem Sie diese Nachricht senden. Dabei kann Cocoa Touch die Anzeige animieren, was Sie über den zweiten Parameter vom Typ BOOL steuern können.
Modale Dialoge in älteren iOS-Versionen
In iOS-Versionen vor 5.0 können Sie für die Anzeige modaler Dialoge die Methode presentModalViewController:animated: verwenden. Über die Property modalViewController des präsentierenden Viewcontrollers können Sie auf den modalen Viewcontroller zugreifen. Sowohl die Methode als auch die Property hat Apple jedoch mit iOS 6 als veraltet gekennzeichnet.
Die Anzeige eines modalen Dialogs läuft in folgenden Schritten ab:
- Erzeugung des Viewcontrollers für die Anzeige oder Verwendung eines serialisierten Viewcontrollers aus dem Storyboard beziehungsweise einer XIB-Datei
- Parameterübergabe an den modalen Viewcontroller
- Konfiguration der Anzeigeoptionen
- Anzeige des Viewcontrollers
Für den ersten Schritt gibt es unterschiedliche Möglichkeiten. Wenn Sie Ihre Views über XIB-Dateien definieren, können Sie ein neues Objekt für den Viewcontroller anlegen und dabei die XIB-Datei angeben (siehe Listing 4.1). Alternativ können Sie den Viewcontroller auch als serialisiertes Objekt in der XIB-Datei des präsentierenden Viewcontrollers ablegen und ihn über ein Outlet referenzieren. Abbildung 4.13 stellt diese Struktur schematisch dar. Die XIB-Datei der Klasse MainViewController, dessen Objekt (A) die Datei MainWindow.xib enthält, beherbergt dessen View und ein Objekt (B) der Klasse ModalViewController. Der View und der Controller liegen in der obersten Ebene in MainViewController.xib. Die Klasse MainViewController besitzt eine Outlet-Property, über die sie auf das jeweilige ModalViewController-Objekt zugreifen kann.
Projektinformation
Sie finden die beschriebenen Strukturen in den Beispielprojekten mit dem Namen Modal. Es gibt sowohl eine XIB-basierte Version Code/Apps/Modal auf der DVD beziehungsweise unter https://github.com/Cocoaneheads/iPhone/tree/Auflage_2/Apps/Modal als auch eine Variante mit Storyboard, die Sie in Code/Apps/Storyboard/Modal beziehungsweise https://github.com/Cocoaneheads/iPhone/tree/Auflage_2/Apps/Storyboard/Modal finden.
Abbildung 4.13 Serialisierter Viewcontroller in einer XIB-Datei
Auf die Viewcontroller in einem Storyboard können Sie jeweils über deren Kennung zugreifen. Dazu verwenden Sie die Methode instantiateViewControllerWithIdentifier: aus der Klasse UIStoryboard. Die Kennung der Viewcontroller legen Sie jeweils über das Eingabefeld Identifier im Attributinspektor des Viewcontroller-Objekts im Storyboard fest. An das Storyboard, aus dem die App den Viewcontroller geladen hat, gelangen Sie über die Property storyboard des Viewcontrollers. Eine Actionmethode in einem Viewcontroller kann also einen weiteren Viewcontroller folgendermaßen deserialisieren:
ModalViewController *theController = [self.storyboard
instantiateViewControllerWithIdentifier:
@"modalController"];
Listing 4.10 Deserialisierung eines Viewcontrollers aus einem Storyboard
Viewcontroller aus einem Storyboard
Im Unterschied zu NIB-Dateien müssen Sie auch den Viewcontroller immer aus dem Storyboard laden, wenn Sie dessen View dort abgelegt haben. Sie können ihn also nicht über alloc und die Methode init oder initWithNibName:bundle: anlegen und initialisieren. Stattdessen erzeugen Sie die Viewcontroller über die Methode instantiateViewControllerWithIdentifier:.
Nachdem Sie das Viewcontroller-Objekt auf einem der beschriebenen Wege erzeugt haben, können Sie ihm Parameter übergeben. Der neue Viewcontroller soll ja in der Regel mit Daten arbeiten, die er von dem aufrufenden Viewcontroller bekommt. Die Parameterübergabe geschieht am einfachsten über Propertys des modalen Viewcontrollers. Im Beispielprojekt Modal übergibt der MainViewController den Text eines Labels an den modalen Dialog. Die Klasse ModalViewController besitzt zu diesem Zweck die Property title. Die Actionmethode weist nun dieser Property einen Wert zu, bevor sie den Viewcontroller anzeigt (siehe Listing 4.11).
- (IBAction)showInfo {
static NSUInteger theCount = 1;
ModalViewController *theController = self.modalController;
theController.title = [NSString stringWithFormat:@"%u", 
theCount++];
theController.modalTransitionStyle = 
UIModalTransitionStyleFlipHorizontal;
[self presentViewController:theController animated:YES 
completion:^{
NSLog(@"View controller presented.");
}];
}
Listing 4.11 Übergabe von Parametern an einen Viewcontroller
Im Beispiel zeigt der Viewcontroller den Text einfach an, indem er in der Methode viewWillAppear: den Wert der Property an die text-Property des entsprechenden Labels übergibt.
- (void)viewWillAppear:(BOOL)inAnimated {
[super viewWillAppear:inAnimated];
self.titleLabel.text = self.title;
}
Listing 4.12 Anzeige des Property-Wertes durch ein Label
Vielleicht fragen Sie sich, warum die Actionmethode showInfo den Titel nicht direkt an das Label übergibt. In Listing 4.11 könnten Sie ja auch theController.titleLabel.text anstelle von theController.title schreiben. Das sollten Sie jedoch nicht machen, da Sie bei der ersten Zuweisung in der Actionmethode zwar das Viewcontroller-Objekt haben; das indes noch nicht seinen View geladen haben muss. In diesem Fall ist das titleLabel-Outlet nil, und die Zuweisung geht ins Leere.
Listing 4.11 weist außerdem der Property modalTransitionStyle einen Wert zu. Über diese Property können Sie die Animation für das Erscheinen und Verschwinden des modalen Views festlegen. Die Animation für das Verschwinden ist dabei jeweils entgegengesetzt zu der Animation für das Erscheinen. Es gibt folgende Auswahlmöglichkeiten:
- UIModalTransitionStyleCoverVertical schiebt den Viewcontroller von unten nach oben in den Bildschirm. Das ist die Standardanimation.
- UIModalTransitionStyleFlipHorizontal dreht die Views an der zentralen, vertikalen Achse umeinander, wie Sie es vielleicht von den Einstellungsdialogen einiger Dashboardwidgets unter OS X kennen.
- UIModalTransitionStyleCrossDissolve blendet den aktuellen View aus und gleichzeitig den modalen View durch einen Überblendeffekt ein.
- UIModalTransitionStylePartialCurl rollt den aktuellen View wie das oberste Blatt eines Kalenders nach oben. Der obere Teil des modalen Views bleibt dabei teilweise verdeckt.
Ein modaler Viewcontroller kann auf den Viewcontroller zugreifen, der ihn anzeigt. Dabei hängt der Weg allerdings von der iOS-Version ab. Bei allen iOS-Varianten vor der Version 5 benutzen Sie dazu die Property parentViewController, während Sie ab Version 5 die Property presentingViewController verwenden müssen. Wenn Ihre App iOS 4 und 5 unterstützen soll, müssen Sie eine Fallunterscheidung einbauen, die allerdings nicht anhand der Betriebssystemversion erfolgen sollte. Es ist sinnvoller, die Existenz des Getters presentingViewController abzufragen.
UIViewController *thePresentingController;
if([self respondsToSelector:
@selector(presentingViewController)]) {
thePresentingController = [self presentingViewController];
}
else {
thePresentingController = [self parentViewController];
}
Listing 4.13 Bestimmung des präsentierenden Viewcontrollers
Abhängigkeiten vermeiden
Durch den Zugriff auf den präsentierenden Viewcontroller erzeugen Sie in der Regel eine Abhängigkeit vom modalen Dialog zu diesem Viewcontroller. Wenn Sie also den modalen Dialog über einen anderen Viewcontroller anzeigen lassen wollen, kann das zu Komplikationen oder weiteren Abhängigkeiten führen. Das endet dann meist in sehr unschönen Fallunterscheidungen und langen Methoden.
Erstellen Sie stattdessen zu der Klasse des modalen Dialogs lieber ein Delegate-Protokoll, und fügen Sie der Klasse eine entsprechende Property für das Delegate hinzu. Der modale Dialog ruft dann die Delegate-Methoden auf und braucht die Klasse des präsentierenden Viewcontrollers nicht zu kennen. Ein sehr schönes Beispiel dafür ist die Klasse UIImagePickerController, die Sie noch im Zusammenhang mit dem Fototagebuch kennenlernen.
4.1.5 Pop-over

Auf dem iPad sind solche modalen Dialoge nicht immer sinnvoll. Häufig brauchen Dialoge nur eine wesentlich kleinere Fläche, als der Bildschirm des iPads bietet, da bei der großen Bildfläche komplette View-Wechsel sehr unruhig wirken können. Stattdessen können Sie auf dem iPad auch ein Pop-over verwenden. Es stellt den Dialog in einen schwarzen Rahmen mit einer Pfeilspitze dar (siehe Abbildung 4.14).
Abbildung 4.14 Anzeige eines Dialogs in einem Pop-over
Die Pfeilspitze zeigt in der Regel auf das Element, über das Sie das Pop-over geöffnet haben. Wenn Sie den Bildschirm außerhalb des Pop-overs berühren, schließt iOS das Pop-over wieder. Dieses Verhalten können Sie verhindern, indem Sie die Property modalInPopover auf YES setzen. Die Logik für die Anzeige von Pop-overn kapselt die Klasse UIPopoverController, die jedoch keine Unterklasse von UIViewController ist.
Für die Anzeige des Pop-overs gibt es zwei Möglichkeiten. Entweder geben Sie einen Button aus der Navigations- oder der Werkzeugleiste an, auf den die Spitze zeigen soll. Dafür verwenden Sie die Methode presentPopoverFromBarButtonItem:permittedArrowDirections:animated: der Klasse UIPopoverController. Dabei ist der erste Parameter ein Button aus einer Navigations- oder Werkzeugleiste. Auf diese Views geht Abschnitt 4.2 noch genauer ein; alternativ können Sie das Pop-over jedoch auch mit der Methode presentPopoverFromRect:inView:permittedArrowDirections:animated: über einem beliebigen View öffnen, den Sie als zweiten Parameter angeben. Mit dem Rechteck im ersten Parameter können Sie die Fläche für die Spitze im View genauer eingrenzen.
UIPopoverController *theController = [[UIPopoverController
alloc] initWithContentViewController:theViewController];
theController.popoverContentSize =
theViewController.view.frame.size;
[theController presentPopoverFromRect:theButton.bounds
inView:theButton
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
self.popoverController = theController;
[theController release];
Listing 4.14 Öffnen eines Pop-overs
Ein Pop-over braucht Halt
Sie müssen nach der Anzeige eine haltende Referenz auf das Pop-over besitzen, da das Betriebssystem diesen Controller nicht hält. Aus diesem Grund weist Listing 4.14 den Controller auch der Property popoverController zu. In der Regel brauchen Sie diese Referenz auch, um das Pop-over aus dem Programmcode heraus wieder zu schließen. Dazu verwenden Sie die Methode dismissPopoverAnimated:.
Beim Öffnen des Pop-overs geben Sie über den Parameter permittedArrowDirections: die möglichen Richtungen der Spitze an. Sie sollten für die Ausrichtung immer sinnvolle Werte verwenden. Andernfalls kann Cocoa Touch das Pop-over schon mal an einer ungewöhnlichen Stelle positionieren. Am einfachsten verwenden Sie die Konstante UIPopoverArrowDirectionAny. Dann wählt iOS automatisch eine geeignete Ausrichtung.
Der Pop-over-Controller aus Listing 4.14 verwendet die Größe des Views für die Anzeige, die Sie über den Interface Builder setzen können. Dazu müssen Sie zunächst im Attributinspektor des Viewcontrollers, der der Variable theViewController im Listing entspricht, in der Rubrik Simulated Metrics im Feld Size den Wert Freeform einstellen. Durch diese Einstellung können Sie die Größe des Views des Controllers über dessen Größeninspektor beliebig ändern. Außerdem sollten Sie das Häkchen vor Resize View From NIB in der Rubrik View Controller deaktivieren, damit Cocoa Touch die Größe des Views nicht automatisch setzt. Die Einstellungen für den Viewcontroller stellt Abbildung 4.15 dar.
Abbildung 4.15 Attribute für einen Viewcontroller im Pop-over-Controller
Wenn Sie das Storyboard beziehungsweise die XIB-Datei für die Gerätefamilie iPad angelegt haben, können Sie die Größe in einem Pop-over auch über den Attributinspektor des Controllers setzen. Dazu verwenden Sie in der Rubrik View Controller die Einstellungen unter Popover wie in Abbildung 4.16. Allerdings verändert diese Einstellung nicht die Größe des Views auf der Zeichenfläche; hierzu müssen Sie immer noch die Einstellung Freeform und den Größeninspektor des Views verwenden.
Abbildung 4.16 Setzen der Größe im »Popover« über den Attributinspektor
4.1.6 Übergänge
Wenn Sie ein Storyboard verwenden, können Sie sich durch Übergänge das Öffnen von modalen Dialogen und Pop-overn vereinfachen. In der Regel enthält das Storyboard alle Viewcontroller und die Views der App. Durch Übergänge können Sie jeweils ein Control [Cocoa Touch und der Interface Builder unterstützen hier allerdings nur echte Unterklassen von UIControl aus dem UIKit; für selbst erstellte Controls gilt das Gleiche: Sie müssen leider draußen bleiben.] oder anderen Button aus dem UIKit mit einem Viewcontroller verbinden. Wie Sie Übergänge mit dem Interface Builder anlegen und wie Sie damit einen modalen Dialog öffnen können, haben Sie bereits in Kapitel 3 erfahren: Sie ziehen eine Verbindung von einem beliebigen Control zu einem Viewcontroller und wählen den gewünschten Übergangstyp aus.
Tabelle 4.3 enthält eine Liste mit allen Übergangstypen und den Gerätegruppen, die sie unterstützen. Da es Pop-over-Controller und Splitviews nur auf dem iPad gibt, macht auch nur dort der entsprechende Übergang Sinn.
| Typ | Gerätegruppe / Version | Übergang |
|
Custom |
alle / iOS 5 |
Erlaubt die Implementierung beliebiger |
|
Modal |
alle / iOS 5 |
Zeigt den View des Viewcontrollers als modalen Dialog an. |
|
Pop-over |
iPad / iOS 5 |
Anzeige des Viewcontrollers in einem Pop-over |
|
Push |
alle / iOS 5 |
Schiebt den Viewcontroller auf den Stack des Navigationcontrollers. |
|
Replace |
iPad / iOS 5 |
Wechselt den rechten Viewcontroller (Detailviewcontroller) in einem Splitview aus. |
|
Unwind |
alle / iOS 6 |
Springt in einer Navigationshierarchie zurück zu einem übergeordnetem Viewcontroller; er ist das Gegenstück zu Push. |
|
Embed |
alle / iOS 6 |
Bettet den View eines Viewcontrollers in den View eines anderen ein. Diesen Übergang legen Sie über einen speziellen View und nicht über eine Verbindung an. |
Über den Typ Custom können Sie auch eigene Übergänge erstellen. Sie müssen dafür eine Unterklasse von UIStoryboardSegue schreiben und die Methode perform implementieren. Cocoa Touch ruft diese Methode auf, um den Zielviewcontroller des Übergangs anzuzeigen. In Abschnitt 4.7.1 finden Sie Beispiele für die Übergangstypen Custom sowie Embed, und Abschnitt 4.2.4 zeigt Ihnen die Verwendung des Typs Unwind.
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






















Jetzt bestellen





