iPhone SDK Tutorial deutsch 6 – Storyboard Part 3 – Detail View und Tab Bar Controller

Das ist Part 3 des Storyboard Tutorials in Xcode 4.2. Es geht um einen Tab Bar Controller als Detail View.
Solltest Du die anderen Teile des Tutorials noch nicht gelesen haben und dich noch nicht mit dem Storyboard auskennen, solltest Du mit Part 1 und Part 2 anfangen. Auch dieses Xcode-Projekt baut auf den anderen Tutorials auf, falls Du es also nicht mehr gespeichert hast, kannst Du es hier downloaden: Xcode-Projekt_Storyboard_Tutorial_Part_2.

Jetzt noch eine Übersicht, was Du in diesem Tutorial lernen wirst:

  • Implementieren eines Detail Views einer Table View
  • Implementieren eines Tab Bar Controllers als Detail View
  • Arbeiten mit Segues

1. Die App

Bisher besteht unserer App nur aus einem “Hauptmenü”, über welches man zu einer Tabelle gelangt, die ein paar Spieler auflistet. Wir werden die App insofern erweitern, dass die Spieler nicht nur aus dem Namen bestehen, sondern auch weitere Attribute haben. Diese werden angezeigt, sobald man einen Spieler auswählt. Die Daten werden in zwei Kategorien aufgeteilt, die mit einem Tab Bar Controller dargestellt werden.

2. Das Model

Wir beginnen, indem wir das Model unseres Projekts erweitern. Ein Model enthält die Daten einer App, also in unserem Fall wird das eine Klasse für die Spieler in der Spielerliste sein. Wenn Du noch nichts von der MVC-Struktur (Model-View-Controller) gehört hast, kannst du dich hier einlesen (ein Beitrag darüber kommt bald).

Starte also Xcode und wähle in der Menüleiste File–>Open…, um das bestehende Projekt zu öffnen.

Wie gesagt beginnen wir mit einer Klasse für die Spieler. Eine Klasse erstellt man meist in zwei neuen Dateien. Dazu klickst Du mit der rechten Maustaste auf den Projektordner (“Tutorial6″) und wählst den Menüpunkt “New File…”. Im erscheinenden Dialog benötigen wir das Template “Objective-C class” und nicht wie im zweiten Part eine “UIViewController subclass” (wir wollen ja keinen neuen View Controller erstellen). Klicke doppelt auf das Symbol und gibt dann bei Class ”Player” ein. Achte darauf, dass bei Subclass of “NSObject” ausgewählt ist. Den Speicherort ändern wir nicht, sondern klicken gleich auf “Create”.

Bevor ich den folgenden Code erkläre, ersetze mit ihm den Code in der jeweiligen Datei:

Player.h:

#import <Foundation/Foundation.h>

@interface Player : NSObject {
    NSString *_name;
    NSNumber *_score;

    NSString *_country;
    NSString *_city;
}

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSNumber *score;

@property (nonatomic, copy) NSString *country;
@property (nonatomic, copy) NSString *city;

-(id) initWithName: (NSString *) newName score: (NSNumber *) newScore country: (NSString *) newCountry city: (NSString *) newCity;

@end

Player.m:

#import "Player.h"

@implementation Player
@synthesize name = _name;
@synthesize score = _score;
@synthesize country = _country;
@synthesize city = _city;

-(id) initWithName:(NSString *)newName score:(NSNumber *)newScore country:(NSString *)newCountry city:(NSString *)newCity {
    self = [super init];
    if (nil != self) {
        self.name = newName;
        self.score = newScore;
        self.country = newCountry;
        self.city = newCity;
    }
    return self;
}

@end

Im Großen und Ganzen sieht so immer eine Klasse eines Models aus. Wir deklarieren in Player.h ein paar Variablen und eine Methode, mit der wir die Werte später definieren können. In Player.m wird diese Methode lediglich definiert.

Bei genauerem Betrachten stellt man allerdings fest, dass diese Klasse etwas anders aussieht. Wenn Du dir “Player.h” nochmal anschaust, wirst Du feststellen, dass die Instanzvariablen, also die Variablen zwischen den geschweiften Klammer, einen Underscore “_” haben. Das heißt mit @synthesize name = _name weisen wir der Property name die Instanzvariable _name zu. Die Erklärung ist recht simpel:
Mit @property erstellt man ja bekanntlich getter- und setter-Methoden für eine Variable. Mit der getter-Methode erhält man dann den Wert der Variable und mit der setter-Methode kann man diesen Wert ändern. Der Zugriff auf diese Methode erfolgt mit self.variable. Würde man das self weglassen, so würde man nicht auf die Property, sondern auf die Variable an sich zugreifen. Und dies wäre falsch, da man dann nicht die getter- bzw. setter-Methode verwendet. Indem man die Variable nun mit einem Underscore deklariert (bspw. _variable) und dann bei @synthesize variable=_variable schreibt, schütz man sich selbst davor, aus Versehen die Variable statt der Property zu verwenden.

Einen weiteren Unterschied kann man in “Player.h” feststellen. Hinter @property steht statt wie sonst (nonatomic, strong) oder (nonatomic, weak) diesmal copy. Ich möchte an dieser Stelle nicht allzu genau auf dieses Stichworts eingehen, da man dafür etwas tiefer in das Memory Management eintauchen müsste, was den Rahmen dieses Tutorial absolut sprengen würde. Man kann sich aber einfach merken, das man Properties vom Typen NSString, NSArray, NSDictionary, NSNumber, also Typen mit NS, meistens mit copy erstellt. Allerdings werden Properties mit Typen, die noch ein Mutable enthalten, also z.B. NSMutableArray, NSMutableDictionary etc., meistens mit strong deklariert.

Die init-Methode kommt jetzt auch gleich zum Einsatz. Deswegen müssen wir die Klasse Player in PlayerlistViewController einbinden. Schreibe Folgendes unter die erste #import-Zeile in “PlayerlistViewController.m”:

#import "Player.h"

Im vorherigen Teil haben wir die Spieler einfach in viewDidLoad als Zeichenketten, also NSStrings, deklariert und in einem Array (playerList) gespeichert. Da wir jetzt aber ein aufwendigeres Model haben, müssen wir diese Methode abändern:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.playerList = [NSMutableArray arrayWithCapacity:20];

    Player *player1 = [[Player alloc]initWithName:@"Andreas" score:[NSNumber numberWithInt:40000] country:@"Deutschland" city:@"Regensburg"];
    [self.playerList addObject:player1];

    Player *player2 = [[Player alloc]initWithName:@"Stefan" score:[NSNumber numberWithInt:35000] country:@"Deutschland" city:@"Regensburg"];
    [self.playerList addObject:player2];

    Player *player3 = [[Player alloc]initWithName:@"Alex" score:[NSNumber numberWithInt:55400] country:@"Deutschland" city:@"Regensburg"];
    [self.playerList addObject:player3];

}

Wir erstellen einfach drei verschiedene Spieler und fügen sie der Spieler-Liste hinzu. Zu beachten ist, dass obwohl wir für jedes Objekt mit alloc Speicher reservieren, wir kein einziges Mal release aufrufen. Das bleibt uns dank dem Automatic Reference Counting erspart, denn dadurch wird der Speicher automatisch freigegeben. Versuchten wir dies mit der release-Anweisung manuell zu tun, würde Xcode sogar einen Fehler auswerfen, da wir beim Erstellen des Projekts in Part 1 des Tutorials eingestellt haben, dass wir ARC benutzen wollen.

viewDidLoad ist aber nicht die einzige Methode die wir ein bisschen verändern müssen. Logischerweise ist tableView:cellForRowAtIndexPath: auch nicht mehr ganz aktuell. Ändere die Methode wie folgt:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PlayerCell"];
    Player *player = [self.playerList objectAtIndex:indexPath.row];
    cell.textLabel.text = player.name;

    // Configure the cell...

    return cell;
}

Da im Array playerList nicht mehr nur einfach NSStrings gespeichert sind, sondern Player-Objekte, müssen wir den passenden Eintrag in einem temporären Player-Objekt speichern und dann der Zelle den Spielernamen zuweisen.

Bisher haben wir die App nicht erweitert, sondern sie nur vorbereitet für den nächsten Schritt. Bevor wir zu diesem übergehen, testen wir, ob noch alles wie gehabt funktioniert. Führe dazu die App aus. Die Tabelle mit den Spielern sollte ganz normal angezeigt werden.

3. Der Tab Bar Controller

Wir wollen, dass wenn eine Tabellen-Zeile ausgewählt wird, ein Tab Bar Controller angezeigt wird. Diesen werden wir jetzt im Storyboard erstellen.

Öffne die Datei “MainStoryboard.storyboard” und suche in der Library nach dem Tab Bar Controller. Bevor du das Object in den Editor ziehst, kannst du noch herauszoomen, damit Du ein besseren Überblick hast. Ziehe den Controller am besten neben den Table View Controller.

Tipp: Wenn du im Nachhinein mehrere Controller auf einmal verschieben möchtest, kannst du mit gedrückter cmd-Taste die einzelnen Docks anklicken und die ausgewählten Elemente zusammen verschieben.

Damit das Ganze seine Ordnung hat geben wir den Tabs noch eine aussagekräftige Bezeichnung. Zoome also wieder heran und klicke im ersten View Controller doppelt auf den Text in der Tab Bar (beachte, dass du im View Controller, nicht im Tab Bar Controller, auf die Tab Bar klicken musst). Gib einfach “Spiel-Charakter” ein. Das zweite Tab Bar Item können wir im zweiten View Controller bearbeiten. Nenne es “Account”.

 Wie Du siehst ändert sich die Tab Bar im Tab Bar Controller automatisch mit.

Zunächst fügen wir den beiden View Controller noch Objects hinzu. Alles was wir benötigen sind ein paar Labels. Ziehe sie, wie in der Abbildung gezeigt, in die View Controller. Anschließend beschriften wir die Labels und ändern die Größe der rechten Labels, damit auch längere Namen in ihnen Platz haben.

Das Interface der beiden View Controller ist damit fertig.

4. Die View Controller Im Code

Als Nächstes werden wir die Dateien für die beiden View Controller erstellen. Dadurch können wir später den Text der Labels der Controller setzen, sodass Name, Höchstpunktzahl, Land und Stadt richtig angezeigt werden.

Klicke mit der rechten Maustaste auf den Projektordner und wähle “New File…”. Klicke im erscheinenden Fenster auf das UIViewController subclass-Template.(Xcode 4.2)

Xcode 4.3: Klicke im erscheinenden Fenster auf das Objective-C class-Template. Im nächsten Fenster sollte bei Subclass of ”UIViewController” ausgewählt sein.

Bei Class schreiben wir “CharacterInformationViewController”. Beachte, dass weder ein Häkchen bei “Targeted for iPad” noch bei “With XIB for user Interface”, gesetzt sein sollte. Die Subclass sollte auf “UIViewController” eingestellt sein.

Klicke auf Next und dann auf Create; wir speichern die Dateien an Ort und Stelle ab.

Wiederhole diesen Schritt (ab 4.) für einen weiteren View Controller namens “AccountInformationViewController”.

Diese Dateien müssen wir als nächstes einem View Controller im Storyboard zuweisen. Öffne wieder die Datei “MainStoryboard.storyboard”, wenn sie nicht schon geöffnet ist, und wähle den “Spiel-Charakter”-View Controller aus. Lass ihn dir dann im Identity inspector anzeigen und trage bei Class den Namen des ersten View Controllers, “CharacterInformationViewController”, ein.

Wiederhole auch diesen Schritt beim anderen View Controller.

Da wir die Labels auf der rechten Seite später im Code bearbeiten möchten, sodass sie die Informationen des Spielers anzeigen, erstellen wir Outlets für diese Labels.

Dazu stellen wir den Editor Modus mit Hilfe des mittleren Button bei “Editor” in der Tool Bar auf Assistant editor. Wähle dann im Storyboard den “Character Information View Controller” aus. Auf der rechten Seite sollte die Datei “CharacterViewController.h” im Code-Editor angezeigt werden.

Alles weitere ist jetzt ganz einfach. Wie immer klicken wir mit gedrückter ctrl-Taste auf das Object, also das “Label”-Label neben “Spieler-Name:” und ziehen den blauen Faden in den Code-Editor zwischen @interface und @end. Nenne das Outlet “nameLabel”.

Auch diesen Schritt wiederholen wir für das Label rechts neben dem Label “Höchstpunktzahl:” und die anderen, welche sich im “AccountInformationViewController” befinden. Diese Outlets werden deshalb logischerweise in “AccountInformationViewController.h” deklariert. Nenne die Outlets “scoreLabel”, “countryLabel” und “cityLabel”.

Für diese Labels sollen die Outlets erstellt werden.

Wenn Du fertig bist, stelle den Editor wieder auf Standard editor ein. Weiter geht’s. Als nächstes erstellen wir die Variablen für die Daten des Spielers. Wir deklarieren sie im CharacterInformationViewController bzw. im AccountInformationViewController. Wenn eine Zeile ausgewählt wird, können wir dann später diesen Variablen den je nach ausgewähltem Spieler passenden Wert zuweisen. Ändere die angegebenen Datei wie folgt ab:

CharacterInformationViewController.h

#import <UIKit/UIKit.h>

@interface CharacterInformationViewController : UIViewController {
    NSString *_name;
    NSNumber *_score;
}
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UILabel *scoreLabel;
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSNumber *score;

@end

AccountInformationViewController.h

#import <UIKit/UIKit.h>

@interface AccountInformationViewController : UIViewController {
    NSString *_country;
    NSString *_city;
}
@property (weak, nonatomic) IBOutlet UILabel *countryLabel;
@property (weak, nonatomic) IBOutlet UILabel *cityLabel;
@property (copy, nonatomic) NSString *country;
@property (copy, nonatomic) NSString *city;

@end

Für den Namen, das Land und die Stadt erstellen wir je einen NSString und für die Höchstpunktzahl eine NSNumber. Außerdem legen wir noch die properties für die Variablen an, da wir später von außen auf sie zugreifen werden. Zu jedem @property gehört wie immer ein @synthesize. Füge deshalb folgenden Code unter die anderen @synthesize-Zeile in der jeweiligen Datei ein.

CharacterInformationViewController.m

@synthesize name=_name;
@synthesize score=_score;

AccountInformationViewController.m

@synthesize country=_country;
@synthesize city=_city;

Damit die Daten des Spielers dann auch angezeigt werden, müssen wir jetzt noch den Text der Labels setzen, bevor der View angezeigt wird. Dazu ändern wir die Methode viewDidLoad in beiden Controller ab.

CharacterInformationViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.nameLabel.text = self.name;
    self.scoreLabel.text = [self.score stringValue];
}

AccountInformationViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.countryLabel.text = self.country;
    self.cityLabel.text = self.city;
}

Endlich sind die beiden View Controller des Tab Bar Controllers fertig und bereit aufgerufen zu werden.

5. Eine Tabellenzeile auswählen

Nun kommen wir zum wichtigsten Teil. Wie können wir nun den Tab Bar Controller anzeigen lassen, wenn eine Tabellenzeile angetippt wird?
In älteren Xcode-Versionen haben wir dazu die Methode tableView:didSelectRowAtIndexPath: verwendet. Das ist zwar immer noch möglich, allerdings gibt es dank des Storyboards eine bessere Möglichkeit. Und zwar kommen hier die sogenannten Segues ins Spiel. Ich habe sie schon in Part 1 des Tutorials angesprochen, allerdings ohne genauer darauf einzugehen.

Bevor ich die Segues genauer erkläre, sehen wir sie uns im Storyboard an. Öffne die Datei “MainStoryboard.storyboard”. Stelle sicher, dass im Document Outline das Object Table View in der “Playerlist View Controller Scene” ausgeklappt ist, damit die Table View Cell sichtbar ist. Klicke dann mit gedrückter ctrl-Taste auf diese Table View Cell im Document Outline und ziehe den blauen Faden auf den Tab Bar Controller in der “Tab Bar Controller Scene”. Wähle im erscheinenden Menü die Option “Push”.

Daraufhin erscheint innerhalb der “Playerlist View Controller Scene” ein neues Element namens “Segue from UITableViewCell to Tab Bar Controller”. Der lange Name beschreibt einfach Ursprung und Ziel der Segue. Im Editor wird die Segue als Pfeil mit Kreis dargestellt.

Bei Segues ist es so gut wie immer sinnvoll, sie mit einem eindeutigen Identifier auszustatten. Um das zu tun, wählt man die Segue wir ein normales Objects aus, indem man im Editor oder im Document Outline darauf klickt, und öffnet dann den Attributes inspector und gib bei Identifier ”ShowPlayerDetails” ein.

Damit ist der Identifier festgelegt.

Was ist also eine Segue? Segues stellen im Storyboard den Wechsel zwischen zwei Controllern dar. Deshalb auch das Icon eine Segue:

In Part 1 haben wir eine Segue zwischen dem Button im 1. View Controller und dem Table View Controller erstellt. Das bewirkt, dass wenn der Button gedrückt wird, der Table View Controller erscheint. So ist es auch bei der neuen Segue. Sobald eine Tabellenzeile ausgewählt wird, soll der Tab Bar Controller angezeigt werden.

Einen kleinen Unterschied gibt es aber. Wir wollen, dass die Informationen des Spielers in der Tabelle in den View Controllern des Tab Bar Controllers angezeigt werden. Das bedeutet, wir müssen Daten zwischen den beiden Controllern schieben. Früher hätten wir dies innerhalb der Methode tableView:didSelectRowAtIndexPath: bewerkstelligt. Auf diese Methode werden wir diesmal aber gänzlich verzichten und stattdessen mit einer anderen Methode arbeiten: prepareForSegue:sender:.
Diese Methode wird aufgerufen, bevor der Wechsel zwischen den Controllern stattfindet. Das ist der perfekte Zeitpunkt um Daten zu schieben.

Die Methode gehört immer zum Ursprungs Controller, da sie ja noch vor der Transition, also dem Wechsel, aufgerufen wird. Das bedeutet, wir müssen sie in der Datei “PlayerlistViewController.m” definieren. Bevor wir die Methode aber definieren importieren wir noch die Header-Dateien der beiden View Controller des Tab Bar Controllers, da wir diese in der folgenden Methode benötigen. Schreibe also folgenden Code unter die anderen #import-Anweisungen in “PlayerlistViewController.m:

#import "CharacterInformationViewController.h"
#import "AccountInformationViewController.h"

Jetzt kommen wir zur eigentlichen Methode. Füge sie zu den anderen Methode in “PlayerlistViewController.m” hinzu.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"ShowPlayerDetails"]) {
        UITabBarController *detailController = [segue destinationViewController];

        CharacterInformationViewController *detailCharacterInformationTab = [detailController.viewControllers objectAtIndex:0];
        AccountInformationViewController *detailAccountInformationTab = [detailController.viewControllers objectAtIndex:1];
        Player *player = [self.playerList objectAtIndex:[self.tableView indexPathForSelectedRow].row];

        detailCharacterInformationTab.name = player.name;
        detailCharacterInformationTab.score = player.score;
        detailAccountInformationTab.country = player.country;
        detailAccountInformationTab.city = player.city;
    }
}

Nun zur Erklärung:
Zeile 2: prepareForSegue:sender: ist eine allgemeine Methode, die für alle Segues ausgelegt ist, die von einem Controller weggehen. Das können auch mal durchaus mehrere sein. Deshalb wird in dieser Zeile festgestellt, um welche Segue es sich handelt. Da wir vorhin im Storyboard den Identifier festgelegt haben, können wir jetzt ganz einfach rausfinden, ob es sich um die richtige Segue handelt.
Zeile 3: In dieser Zeile erstellen wir einen Tab Bar Controller, der aufzurufende Controller. Um diesen Tab Bar Controller mit dem im Storyboard zu verknüpfen, verwenden wir die Methode destinationViewController des Segue-Arguments, welche uns den Ziel-Controller der Segue zurückgibt.
Zeile 5-6: Zunächst erstellen wir die Instanzen der beiden View Controller des Tab Bar Controllers. Auch diese müssen wir wieder mit dem passenden View Controller im Storyboard verbinden. Diesmal verwenden wir die Methode objectAtIndex des Tab Bar Controllers. Sie liefert uns je nach angegebenen Index den passenden View Controller innerhalb des Tab Bar Controllers. Da man in der Informatik bei 0 zu zählen beginnt, befindet sich der erste Tab auch beim Index 0, der zweite beim Index 1.
Zeile 7: Hier erstellen wir ein Player-Objekt, welches den richtigen Spieler aus der Spielerliste zugewiesen bekommt. Um das richtige Element aus dem Array playerList zu erhalten, verwenden wir [self.tableView indexPathForSelectedRow].row. Das bewirkt, dass in der Table View die vom User ausgewählte Zeile gesucht wird und deren Zeilennummer als Index im Array verwendet wird. Im Prinzip also kein großer Unterschied gegenüber dem, wenn wir mit der Methode tableView:didSelectRowAtIndexPath arbeiten.
Zeile 9-12: Hier weisen wir den Variablen, die wir vorhin innerhalb von CharacterInformationViewController und AccountInformationViewController erstellt haben, den jeweiligen Wert aus dem Player-Objekt zu. Dadurch, dass wir in den viewDidLoad-Methoden der beiden View Controller den Labeln den Wert der Variablen zugewiesen haben, werde die Spieler-Daten im Detail View richtig angezeigt.

Vielleicht fragst Du dich, wieso in dieser Methode nirgends ein neuer View Controller aufgerufen wird. Das liegt daran, dass dies das Storyboard übernimmt. Die Methode prepareForSegue:sender: “bereitet” ja nur die Transition vor. Der eigentliche Wechsel ist dann die Segue an sich.

Pfew! Jetzt erstmal kräftig durchatmen, denn wir sind soweit fertig mit unserer App. Jetzt nur noch hoffen, dass wir keinen Fehler gemacht haben und wir die App fehlerfrei ausführen können. Wenn alles passt funktioniert die App einwandfrei. Wir können einen Spieler der Tabelle auswählen und uns die Daten schön sortiert mit einer Tab Bar anzeigen lassen.

6. Schluss

In diesem Tutorial hast Du viele neue Dinge gelernt. Deswegen, wenn Du noch irgendwelche Fragen hast, ich etwas nicht ausführlich genug erklärt habe oder Du einen Fehler gefunden hast, würde ich mich freuen, wenn Du mir ein Kommentar schreibst.

Lass mich außerdem wissen, ob Du dir ein weiteres Tutorial zum Thema Storyboard wünscht. Auch über Tutorial-Vorschläge jeglicher Art freue ich mich.

Das fertige Xcode Projekt gibt’s wie immer zum Downloaden: Tutorial6_3

Wenn Du möchtest kannst du gerne die Blog RSS abonnieren oder mir auf Twitter folgen.

This entry was posted in iPhone SDK, Tutorial and tagged , , , , , . Bookmark the permalink.

25 Responses to iPhone SDK Tutorial deutsch 6 – Storyboard Part 3 – Detail View und Tab Bar Controller

  1. Klaus says:

    Hallo

    Ich benötige wieder einmal Hilfe. Ich hab keine Ahnung was falsch ist.
    Beim Abtippen deines Tutorials meckert mein Xcode schon ( Roter Kreis mit !).
    Im Player.m hast du die Zeile
    self = [super init]
    drinstehen. Da bekomme ich schon folgende Meldung
    Cannot assign to ‘self’ outside of a method in the init family

    ????????????

    Gruß Klaus

    • Felix says:

      Hallo Klaus,

      sieht mir nach einer fehlenden geschweiften Klammer aus. Überprüfe noch ein Mal alle Klammern. Ansonsten kann ich Dir nur helfen, wenn Du ein paar Codeausschnitte postest.

      Viele Grüße
      Felix

  2. Thomas says:

    Hi Felix,

    grossartiges Tutorial!

    You made my day!

    Cheers Thomas

  3. Iva says:

    Wieder Super, vielen Dank!!!!!

  4. Jimijimbo says:

    Hi,
    auch das Tutorial wieder 1A !

    Danke

  5. Thomas says:

    Ganz tolles Tutorial das sehr gut erklärt ist.
    Da kann man fast nichts schief machen…

    Vielen Dank, ich habe wieder sehr viel gelernt und probiere das gleich umzusetzen…

  6. René says:

    Super Tutorial! Klappt auch alles aber ich möchte gern die Tabbar weg lassen. Bin auch auf dem richtigen Weg, allerdings bereitet mir das letzte Stück Schwierigkeiten..ab – (void)prepareForSegue:
    Einfach den Tabbar-Teil weglassen klappt nicht. So sieht es bei mir aus:

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@”ShowZimmer”]) {

    ZimmerEinzel *Zimmereinzel = [detailController.viewControllers objectAtIndex:0];
    FerienzimmerDetail *Ferienzimmerdetail = [self.Unterktyp objectAtIndex:[self.tableView indexPathForSelectedRow].row];

    Zimmereinzel.name = Ferienzimmerdetail.name;
    Zimmereinzel.ort = Ferienzimmerdetail.ort;

    }
    }

    Wo liegt der Fehler? Beim Klicken schmeißt mich die App einfach raus.

    Vielen Dank schonmal.
    Gruß René

    • Felix says:

      Hallo René,

      So wie ich das sehe, ist “Zimmereinzel” der View Controller der aufgerufen werden soll, wenn eine Zeile ausgewählt wird. Und in “Ferienzimmerdetail” sind die Information über “Zimmereinzel” gespeichert.
      Allerdings müsste ich noch wissen ob und wo “detailController” bzw. auch “Unterktyp” deklariert werden.

      Wie gesagt bräuchte ich einfach noch ein paar mehr Informationen, um dir weiterhelfen zu können.

      Viele Grüße
      Felix

  7. Niki List says:

    Hallo.

    Wirklich ausgezeichnetes Tutorial. Super erklärt und sich dabei niemals im riesigen iOS-Dickicht verloren. Nachbau hat ohne Probleme funktioniert. Kann ich nur weiterempfehlen. War mir auch eine kleine Spende wert :-)

    Niki.

    • Felix says:

      Hallo Niki,

      vielen Dank für deine Spende und das Lob. Das spornt mich noch zusätzlich an, weiter zu machen :-) .

      Viele Grüße
      Felix

  8. Robo.Term says:

    echt klasse tut!!!
    endlich mal eins, in dem mehrere themen in einem abwasch erklärt werden. top!

  9. Andreas Heckel says:

    Hi Felix,
    vielen Dank für das wirklich leicht nachzuvollziehende Tutorial. Auch bei mir hat die App auf Anhieb funktioniert :-) Nun ist mir aber folgendes aufgefallen:

    Wenn man das iPhone in in der Orientierung Portrait hält, funktioniert die App super.
    Hält mal das iPhone in der Orientierung Landscape und klickt die einzelnen Views bist zum AcountInfo-View durch, wird die Orientierung Landscape auf dem “Hinweg” immer schön beibehalten. Aber auf dem “Rückweg” bis zum Hauptmenü wird die Orientierung dann einfach auf Portrait umgestellt, auch wenn ich das iPhone immer noch quer (Landscape) halte.
    Den Effekt zeigt sowohl meine selbst zusammengeklickte App als auch Deine Download-Version.

    Kannst Du mir einen Tipp woran das liegt?

    • Andreas Heckel says:

      Ich gebe mir die Antwort auf meine Frage mal selbst ;-)

      In den ViewControllern ist dafür die Methode shouldAutorotateToInterfaceOrientation anzupassen.

  10. Raphael says:

    Hi,

    super Tutorials! Mach bitte weiter so. Man lernt eine Menge!

    Gruß

  11. Sandro says:

    Hallo, Danke für deine super Tutorials! Wirklich sehr verständlich!

    Eine Idee für ein weiteres Tutorial wäre ev. die Daten per XML in die App zu bringen. Ich versuche mich gerade daran, komme jedoch leider nicht weiter.

    Gruss Sandro

  12. Andy says:

    Ich behaubte, dass die Klassenattribute *name, *score, *country und *city in der Player-Klasse überflüssig sind, weil ja dafür @Properties definiert wurden.

    • Felix says:

      Hallo,

      das stimmt, der Compiler erzeugt automatisch während der Laufzeit die iVars. Es ist allerdings nur zeitsparend. Ich werde es in den neuen Tutorials beachten.

      Grüße
      Felix

  13. Addi says:

    Hallo.

    vielen Dank und großes Lob zu dem tollen Tutorial zum Thema Storyboard.

    Nachprogrammieren hat super funktioniert und auch lerneffekt gehabt.

    Klasse wäre eine Fortführung dieser “Reihe” in der man Spieler in der App selbst anlegen kann.

    Weiter so! Freue mich schon auf die nächsten Tutorials!

    Gruß Addi

    • Felix says:

      Hallo,

      danke schön :-) .
      Ich schreibe gerade am nächsten Tutorial, aber dein Vorschlag kommt auf jeden Fall auf die Liste ;-) .

      Grüße
      Felix

  14. Tobias says:

    Vielen Dank für deine ausführlichen Tutorials, sie helfen mir wirklich sehr weiter mich in das Thema einzuarbeiten.

  15. Marc says:

    Mir gefallein deine Tutorials auch sehr gut! Endlich mal eins auf Deutsch und ausführlich erklärt. Weiter so!

    Ich würde mir folgendes Tutorial wünschen: iPad mit mehreren View-Controllern und der Swipe gehste. Und das ganze auf Landscape Modus beschränkt.

    Wenn ich Tutorials fürs iPhone durchgehe, klappt das ohne Probleme nur mit dem iPad gehts nicht. Bin aber auch blutiger Anfänger und weiß daher absolut nicht wo der Unterschied ist ;-)

    • Felix says:

      Hallo,

      danke für dein Kommentar! Was genau läuft denn auf dem iPad schief?
      Ich hab mir schon länger überlegt, ein Tutorial für das iPad zu schreiben. Ich denke ich werde mich bald mal dran machen.

      Grüße
      Felix

  16. Uwe says:

    Prima Tutorial mit sehr guter Erklärung.
    Nachprogrammieren hat auf Anhieb geklappt.

    Danke für deine Mühe.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*


+ zwei = 9

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>