Dynamischer Aufruf eines UITableViewController oder eines UIViewController mit Hilfe von Segues

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Dynamischer Aufruf eines UITableViewController oder eines UIViewController mit Hilfe von Segues

    Hallo zusammen,

    ich bin neu in der Community und hoffe ihr könnt mir bei meinem Problem helfen :)

    Leider habe ich hierzu noch nichts ganz passendes gefunden.

    Ich möchte eine iPhone-App entwickeln, welche im ersten Schritt eine n Layer tiefe Navigation anzeigt.

    Jedem Navigationspunkt kann eine weitere Navigationsebene ODER eine Maske zugeordnet sein. Beim Klick auf den Navigationspunkt prüfe ich, was von beidem der Fall ist.

    Sollte nun ein Untermenü vorhanden sein, so möchte ich den aktuellen MasterViewController erneut aufrufen und ihm anschließend in prepareForSeque das Submenü mitgeben.

    Ist jedoch eine Maske vorhanden, so möchte ich den DetailViewController aufrufen.

    Ich verwende Storyboards und hatte hier bereits ZWEI Segues definiert, was jedoch dazu führte, dass sie beide unterschiedliche Auslösepunkte hatten.
    Es wurde das Informations-Icon angefügt über welches ich den zweiten Segue ansteuern konnte, was nicht das ist was ich möchte.

    Entferne ich einen oder beide Segues und versuche sie in tableView:didSelectRowAtIndexPath: aufzurufen bekomme ich den (verständlichen) Fehler, dass der entsprechende Segue nicht vorhanden ist, bzw. gefunden wurde.

    Also dachte ich mir ich erstelle einen neuen Segue welcher auf diesen Identifier hört, was aber zu gleichem Ergebnis geführt hatte.

    Ich würde mich sehr freuen, wenn ihr mir behilflich sein könntet.

    Gruß
    ThaHe4dHunt3r

    EDIT: Quellcode angefügt

    Quellcode

    1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. AvERPNavigationItem* navItem = [navigationRows objectAtIndex:indexPath.row];
    4. if ([navItem hasChilds])
    5. {
    6. [self performSegueWithIdentifier:@"showSubNavigation" sender:self];
    7. }
    8. else
    9. {
    10. [self performSegueWithIdentifier:@"showDetail" sender:self];
    11. }
    12. }
    13. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    14. {
    15. NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    16. AvERPNavigationItem* navigationRow = navigationRows[indexPath.row];
    17. if ([[segue identifier] isEqualToString:@"showDetail"])
    18. {
    19. DetailViewController* detailController = [segue destinationViewController];
    20. [detailController setDetailItem:navigationRow];
    21. }
    22. else if ([[segue identifier] isEqualToString:@"showSubNavigation"])
    23. {
    24. MasterViewController* navController = [segue destinationViewController];
    25. [navController setParentNavigationItem:navigationRow];
    26. }
    27. }
    Alles anzeigen
  • Hallo ioscampus,

    danke für deine Antwort. Es handelt sich jedoch nicht um eine iPad App mit SplitViewController.

    1. Mein Problem ist, dass ich keine zwei Segues definieren kann, welche vom gleichen Element angestoßen werden (der NavigationRow) und aber nur einen ausführen.

    2. Im Grunde möchte ich das, da ich die Segues nicht im Storyboard definieren möchte, weil 1.
  • ThaHe4dHunt3r schrieb:


    1. Mein Problem ist, dass ich keine zwei Segues definieren kann, welche vom gleichen Element angestoßen werden (der NavigationRow) und aber nur einen ausführen.


    Warum sollte man soetwas auch tun?

    Definiere zwei allgemeine segues zwischen den Viewcontrollen und gib beiden einen Identifier. Anschließend kannst du im Programm bei der Nutzereingabe (didSelectRowAtIndexPath?) prüfen, welche segue du ausführen möchtest.
    Eventuell führt dich auch shouldPerformSegueWithIdentifier zum Ziel - schwer zu sagen, da ich deine Anforderung noch immer nicht verstehe.

    ThaHe4dHunt3r schrieb:


    2. Im Grunde möchte ich das, da ich die Segues nicht im Storyboard definieren möchte, weil 1.

    ?( Der Staz ist mir zu wirr.
  • Mein Problem liegt schlicht darin, dass ich im Storyboard nicht weiß wie tief die Navigationshierarchie ist und ob unter dem aktuellen Element eine weitere Ebene oder eine Maske liegt, welche ich im Detail anzeigen möchte.

    Daher dachte ich mir ob ich zwei Segues an dieses Element hängen könnte und beim Aufruf den zweiten deaktivieren.

    Dein Vorschlag klingt schon eher nach dem was ich möchte, aber wie kann ich denn "allgemeine" Segues definieren?
    Meines Wissens nach kann ich diese doch lediglich von Element A nach Element B definieren, oder ist das nicht der Fall?

    Danke, dass du versuchst mir zu helfen :)
  • Ich verstehe das auch noch nicht so richtig. Du möchtest eine undefinierte Tiefe von TableViews haben? Wenn ein Eintrag weitere "Untereinträge" hat, soll er den nächsten, zum Eintrag gehörigen TableView öffnen, wenn der Eintrag keine weiteren "Untereinträge" hat, soll er einen DetailView des ausgewählten Eintrags anzeigen?
    Ich bin gegen Signaturen!!!
  • Eventuell löst Du dich komplett von den Seques und erstellst einfach im didSelectRowFromIndexPath selber den ViewController den du brauchst und pushed ihn auf den Stack

    Dann ist das Ganze mit einer If-Adfrage erledigt..

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • @beage: Das ist genau das was ich möchte :)

    @Thallius: In die Richtung hatte ich auch bereits gedacht, leider bin ich komplett neu in der OS X Entwicklung, weshalb ich nur Storyboards kenne.
    Wie kann ich die ViewController denn auf den Stack legen? Das Erzeugen sollte ja über die Initializier, bzw. Komfortinizializer funktionieren.
  • Guten Morgen Claus,

    das habe ich nun wie folgt eingebaut:

    Quellcode

    1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. AvERPNavigationItem* navItem = [navigationRows objectAtIndex:indexPath.row];
    4. if ([navItem hasMask])
    5. {
    6. DetailViewController* maskController = [DetailViewController new];
    7. [maskController setDetailItem:[AvERPAPI doRequestMask:[navItem getMaskName]]];
    8. [self.navigationController pushViewController:maskController animated:YES];
    9. return;
    10. }
    11. else if ([navItem hasChilds])
    12. {
    13. MasterViewController* subNavController = [MasterViewController new];
    14. [subNavController setParentNavigationItem:navItem];
    15. [self.navigationController pushViewController:subNavController animated:YES];
    16. return;
    17. }
    18. else
    19. {
    20. return;
    21. }
    22. }
    Alles anzeigen



    Leider bekomme ich nun beim Aufruf einer Sub-Navigation die folgende Exception:

    Quellcode

    1. *** Assertion failure in -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:5261
    2. *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'



    Außerdem funktioniert auch kein Aufruf eines DetailViewController. Dieser wird zwar auf den Stack gelegt und somit angezeigt, jedoch komplett Schwarz.
    Vorerst soll er lediglich die Description des übergebenen DetailItem anzeigen, sodass ich sehe, dass es funktioniert. Das hatte mit den Segue's auch beides funktioniert :(

    Irgendetwas mache ich wohl immernoch falsch
  • Ich habe das nun wie folgt gelöst:

    Quellcode

    1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. AvERPNavigationItem* navItem = [navigationRows objectAtIndex:indexPath.row];
    4. UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil];
    5. if ([navItem hasMask])
    6. {
    7. AvERPMask* mask = [AvERPAPI doRequestMask:[navItem getMaskName]];
    8. if (mask)
    9. {
    10. MaskViewController* maskController = (MaskViewController*)[storyboard instantiateViewControllerWithIdentifier:@"maskVC"];
    11. [maskController setDetailItem:mask];
    12. [self.navigationController pushViewController:maskController animated:YES];
    13. }
    14. return;
    15. }
    16. else if ([navItem hasChilds])
    17. {
    18. NavigationViewController* subNavController = (NavigationViewController*)[storyboard instantiateViewControllerWithIdentifier:@"navVC"];
    19. [subNavController setParentNavigationItem:navItem];
    20. [self.navigationController pushViewController:subNavController animated:YES];
    21. return;
    22. }
    23. return;
    24. }
    Alles anzeigen


    P.S.: Wie kann ich das Thema als gelöst markieren? ;)
  • dein ursprünglichen Fehler vom "Montag, 25. November 2013, 09:34" zu beheben ist relativ einfach
    a) Geh ins Storyboard zum TableViewController - wähle die TableView aus und im Inspector findest Du irgendwo den CellIdentifier -> hier einen eigenen Namen vergeben
    b) Neues Projekt "MasterView" o.s.ä. öffnen und da in den Quellcode für die Methode tableView:didSelectRowAtIndexPath: sehen, wie der CellIdentifier aufgerufen wird und bei Dir reinkopieren mit dem Wert aus a). Damit bist Du erstmal die Fehlermöglichkeit los.

    Wenn dann Dein Code "if ([navItem hasMask])" auch ein vernünftiges Ergebnis rauswirft (YES oder NO :) ), solltest Du zumindest in die richtige Funktion reinlaufen ... ohne Fehlermeldung.

    Zu Deinem eigentlichen Ansatz:
    Du möchtest abhängig von der gewählten Zeile einen bestimmten Segue aufrufen?! Das geht grundsätzlich auch mit Segues. Du kannst einfach von dem Haupt-ViewController mit Ctrl-Klick auf einen anderen ViewController einen Segue erstellen. Ohne konkreten Bezug auf die Prototyp-Tabellenzeile!

    Was musst Du dafür noch an Code zum Interpretieren bauen?
    Zu erst brauchst Du erst einmal die Methode prepareForSegue:sender: im Code (bitte kurz googlen, da findest Du dann schnell praktische Beispiele, wie man unterschiedliche Controlleraufruft). Innerhalb der Methode kannst Du mit
    if([[segue identifier] isEqualToString:@"DeinSegueIdentiferAusDemSoryboard"]) {}
    eine Unterscheidung treffen. Dazu musst Du jedem Segue im Storyboard einen eigenen Identifierwert zu weisen (muss man aber glaub ich eh machen, sonst ähnlicher Fehler wie bei TableView).

    Wie bekommst Du nun den Aufruf der Methode hin. Auch ganz einfach:
    [self performSegueWithIdentifier:@"DeinSegueIdentiferAusDemSoryboard" sender:sender];

    Jetzt wird es in Deiner App knifflig. Du willst ja aus unterschiedlichen Zellen unterschiedliche Segues aufrufen. Also musst Du in jeder selectedRow eine Fallunterscheidung einbauen. Bekomm ich jetzt auswendig nicht hin, aber da solltest Du mit Deinem alten Quellcode irgendwie weiterkommen bzw. einfach mal die didSelectRowAtIndexPath: Methode in Verbindung mit dem guten alten "Switch-Case" googlen.

    Deine erste Hürde Segues nicht direkt an die Prototyp-TableCell zu knüpfen, sondern vom HauptController (i.d. Regel bei Dir wahrscheinlich der "TableViewController") und dann Aufruf mit [self perform... bzw. Einbau der dazugehörigen Methode prepareFor... sowie der dortigen Fallunterscheidung sollten Dir genug Ansätze zum weiteren Try&Error geben.

    Viel Spaß & gruß
    iet
    ----
    Macht's gut und danke für den Fisch