Suite adaptative dans le storyboard Xcode 6. Le push est-il obsolète?

121

Le constructeur d'interface Xcode 6 a par défaut une nouvelle case à cocher "utiliser les classes de taille". Cela rend les vues adaptatives. entrez la description de l'image ici

Lorsque j'essaye de faire la transition entre 2 vues dans mon storyboard, j'ai de nouvelles options: entrez la description de l'image ici

plutôt vieux:

entrez la description de l'image ici

Maintenant, nous avons "show" et "present modal" au lieu de "push" et "modal". Les anciennes options sont marquées comme obsolètes. J'ai choisi l'option "afficher", car dans les paramètres de segue, elle s'appelait "show (par exemple, push)

entrez la description de l'image ici

Mais ça ne pousse pas. L'animation Segue ressemble à une diapositive à partir du bas (modale) et la barre de navigation disparaît.

La question est: Comment puis-je faire fonctionner "show" comme push? Est-ce possible ou devrais-je utiliser "push (obsolète)" à la place? Où puis-je trouver des informations sur les nouveaux types de segue? La seule chose que j'ai trouvée dans la bibliothèque des développeurs iOS8 est les storyboards qui vous aident à concevoir votre interface utilisateur, mais il n'y a aucune information sur la séquence "show".

METTRE À JOUR

J'ai essayé de créer un nouveau projet et "show" fonctionne vraiment comme "push". Je pense que le problème dans mon projet peut être dû au fait que je réutilise le contrôleur de navigation avec un code comme celui-ci, mais je ne sais pas comment le résoudre.

if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
    SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
    
    swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
        
        UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
        [navController setViewControllers: @[dvc] animated: NO ];
        [self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
    };
    
}

Après cela, j'essaye de pousser NewViewController après MainViewController entrez la description de l'image ici

MISE À JOUR 2:

Il semble que je ne sois qu'un problème avec iOS 7, iOS 7.1.

John Kakon
la source

Réponses:

97

Oui, utilisez "Afficher" au lieu de "Pousser"

Comment puis-je faire fonctionner "show" comme push? Est-ce possible ou devrais-je utiliser "push (depricated)" à la place?

Cela devrait; ça fait pour moi. J'utilise Xcode 6 beta 2 et pour tester j'ai utilisé le modèle de vue unique (appelant le contrôleur de vue pré-fait dans IB 'VC_A'). J'ai ensuite ajouté un autre contrôleur de vue ('VC_B'). J'ai ensuite ajouté un bouton sur VC_A pour afficher VC_B et un autre de VC_B vers VC_A. Lorsque j'ajoute un contrôleur de navigation comme contrôleur de vue initial dans le storyboard et que je fais de VC_A le rootViewController, les deux 'push' et 'show' ont le même effet. Si je n'ai pas de contrôleur de navigation initial et que j'utilise «show», j'obtiens ce que vous avez décrit en ce que le VC_B fait un glissement de bas en haut. Si j'essaye de «pousser», j'obtiens un crash car pour pouvoir pousser, je dois avoir un contrôleur de navigation.

Où puis-je trouver des informations sur les nouveaux types de segue?

J'ai donc trouvé des informations dans la session «Quoi de neuf dans Interface Builder» ici . Si vous regardez les diapositives, vous verrez une diapositive (41) mentionnant le changement. Lorsque vous regardez cette vidéo de session, vous pouvez passer à la minute 38:00 où ils commencent à parler de segues adaptatives. Ils expliquent que la séquence adaptative «show», par exemple, prend en compte le contexte pour décider comment faire la présentation d'un nouveau contrôleur de vue.

Spencer Hall
la source
Merci pour votre réponse. J'ai essayé de créer un nouveau projet et "show" fonctionne vraiment comme push avec le contrôleur de navigation. Dans mon projet, j'ai une structure compliquée avec la barre latérale de cette leçon appcoda.com/ios-programming-sidebar-navigation-menu et push fonctionne, pas le spectacle. Peut-être que la raison est que je réutilise le contrôleur de navigation. J'ai mis à jour ma question avec le code de réutilisation.
John Kakon
Donc, la première chose que je vois en regardant votre mise à jour est que vous utilisez l'attente d'un segue personnalisé: 'SWRevealViewControllerSegue' alors oui, cela n'a probablement pas de sens d'utiliser 'show' ou 'push' dans votre cas puisque ceux-ci sont intégrés segues alors que vous souhaitez exécuter votre propre code personnalisé. Lorsque je télécharge l'exemple de projet, il affiche même la sélection de «personnalisé» sur les segments dans le fichier de storyboard.
Spencer Hall
Je ne voulais pas dire cette séquence. Je parlais de la création d'un nouveau UIViewController à côté de "MainViewController" (il a un contrôleur de navigation, et ma "mise à jour" montre seulement comment puis-je y arriver) et tente de pousser une nouvelle vue dans MainViewController. Capture d'écran du Storyboard Je vous serai reconnaissant si vous activez "utiliser les classes de taille" dans l'exemple de projet, créez NewViewController et essayez de faire la transition entre MainViewController et NewViewController par "show". Vous verrez de quoi je parle.
John Kakon
A fait ça tout à l'heure et au moins pour moi "show" fonctionnait comme "push".
Spencer Hall
9
Vous pouvez contourner le bogue en vous assurant que tous les chemins dans votre contrôleur de vue ont un UINavigationController à leur racine. Même si cela signifie mettre un UINavigationController dans votre storyboard qui ne sera jamais accessible. Il semble que le câblage soit utilisé pour déduire le comportement.
Scott Robertson
33

Il y a déjà une réponse acceptée, mais je voulais donner un peu plus d'informations, peut-être des informations qui n'étaient pas disponibles auparavant.

Comme mentionné précédemment, les segments "push" et "modal" ont été désapprouvés et ont été remplacés respectivement par "show" et "present modally". Selon la documentation d'Apple, les nouvelles segues ont été divisées en segments qui s'adaptent aux classes de taille. Les plus anciens ne doivent être utilisés que pour prendre en charge les versions iOS antérieures à iOS 8.

Le document dans le lien suivant explique cela et la description de tous les segments disponibles, anciens et nouveaux.

Ajout d'un segment entre les scènes dans un storyboard

Au cas où l'URL changerait à l'avenir, voici l'explication donnée pour chaque nouvelle séquence:

Spectacle

Présentez le contenu dans la zone de détail ou maître en fonction du contenu de l'écran. Si l'application affiche une vue principale et détaillée, le contenu est poussé dans la zone de détail. Si l'application n'affiche que le maître ou le détail, le contenu est poussé au-dessus de la pile de contrôleurs de vue actuelle.

Montrer les détails

Présentez le contenu dans la zone de détail. Si l'application affiche une vue principale et détaillée, le nouveau contenu remplace le détail actuel. Si l'application n'affiche que le maître ou le détail, le contenu remplace le haut de la pile de contrôleurs de vue actuelle.

Présent modalement

Présentez le contenu de manière modale. Il existe des options pour choisir un style de présentation (UIModalPresentationStyle) et un style de transition (UIModalTransitionStyle).

Présent en Popover

Présentez le contenu sous forme de popover ancré à une vue existante. Il existe une option pour spécifier les directions possibles de la flèche affichée sur un bord de la vue popover (UIPopoverArrowDirection). Il existe également une option pour spécifier la vue d'ancrage.

alondono
la source
24

tldr; Supprimez le Segue qui ne pousse pas correctement et recréez-le dans le storyboard en le faisant glisser d'un UIView / UIControl vers le contrôleur de vue cible.

Il n'y a rien de mal avec les autres réponses, mais celle-ci explique ce qui se passe, comment vous pouvez vérifier que cela se produit et comment atténuer le problème à l'avenir.

Contexte

Dans mon cas, aucun de mes Show Segues ne fonctionnait même si j'avais déjà un UINavigationController comme contrôleur de vue initial (avec mon contenu UIViewController comme root).

Pourquoi et comment le show Segue se rompt

La séquence Afficher s'interrompt lorsqu'une action est associée à la séquence dans le xml source du storyboard. Un scénario typique à l'origine de cela pourrait être si vous avez redéfini une segue à partir d'un segue manuel précédemment appelé dans le code. Cela laisse les éléments suivants dans le storyboard xml.

<connections>
    <segue destination="85t-Z1-hxf" kind="show" identifier="ToOptions" action="showDetailViewController:sender:" id="gdZ-IX-KcN">
</connections>

Nota Bene Pour afficher le storyboard au format xml; Cliquez avec le bouton droit sur le fichier du storyboard et choisissez Ouvrir en tant que> Code source . Pour revenir, utilisez Ouvrir en tant que> Interface Builder - Storyboard

Pour s'adapter à toutes les actions personnalisées lors de l'utilisation du segue à partir du storyboard, il suffit de taper sur prepareForSegue et d'intercepter le contrôleur de vue de destination et d'appeler toutes les méthodes à partir de cet emplacement. Dans tous les cas, l'effet secondaire de ce petit bogue (le bogue est le fait que lorsque vous redéfinissez la segue elle n'est pas correctement configurée en xml ~ c'est à dire que l'action reste même après avoir changé la segue en une qui opère à partir d'un UIView (ou UIControl) vers un contrôleur de vue cible).

Malheureusement, la solution la plus directe échoue. Donc, simplement supprimer l'attribut xml pour l'action dans le Storyboard ne résoudra PAS le problème. Au lieu de cela, il faut simplement supprimer et recréer la séquence dans le storyboard.

Une fois recréé, le storyboard xml n'aura plus d'action associée à la séquence particulière et le spectacle s'exécutera en tant que Push.

Exemple de XML pour un Show Segue correct

  <connections>
    <segue destination="RbV-Au-WV9" kind="show" identifier="ToOptions" id="5dm-os-bcS"/>
  </connections>

Atténuation

Pour éviter la récurrence, il suffit de s'en tenir aux segues de storyboard non manuels si possible en utilisant le prepareForSegue pour ajouter les actions requises en fonction du contrôleur de vue de destination. Ou si vous devez mélanger et assortir, prenez la précaution de vérifier que vos segues Show n'ont aucune action attachée dans le storyboard xml. Si vous avez affaire à des projets plus anciens, vous devez accorder une attention particulière au code source de Storyboard car j'ai découvert quelques problèmes.

Tommie C.
la source
3
Après des heures, cela m'a probablement sauvé d'autres heures. Voici ce que je suggérerais sur la base de ce qui précède: Ouvrez le storyboard en tant que code source , recherchez kind = "show" et regardez si la ligne contient quelque chose comme action = "showDetailViewController: sender:" , si c'est le cas, supprimez tout de l' action = jusqu'à la fermeture " . J'ai un énorme storyboard et la séquence affectée ne contenait pas ce paramètre d'action, mais une autre ligne non liée le contenait. Une fois que j'ai supprimé l'action, toutes les séquences adaptatives ont fonctionné à nouveau comme prévu. La simple suppression de la séquence affectée n'a pas fonctionné. t travail.
Marcus
Cela m'a sauvé aussi.
Adam Bardon
1
La suppression de l'attribut d'action dans le XML a fonctionné pour mon ami.
Brent Royal-Gordon
m'a sauvé aussi
Jimmy George Thomas
Supprimé l'attribut d'action dans le fichier xml, et voila, cela fonctionne. Je n'aurais jamais trouvé le problème sans cet article.
krizzzn
20

Comme Scott Robertson l'a commenté ici , cela ressemble à un bogue dans iOS 7.

Il semble que dans iOS 8, la transition soit déduite à l'exécution (comportement correct), tandis que dans iOS 7, la transition est déduite au moment de la conception (comportement bogué).

La solution de contournement la plus simple consiste à ajouter un contrôleur de navigation inutilisé au storyboard et à le lier afin que le contrôleur de vue en question fasse partie de ce contrôleur de navigation. Vous n'avez pas réellement besoin d'instancier le contrôleur de navigation, vous avez juste besoin du contrôleur de vue buggy pour savoir qu'il est intégré dans un contrôleur de navigation.

Remarque: la simulation d'une barre de navigation n'est pas suffisante à ces fins; vous devez en fait avoir un contrôleur de navigation dans sa pile de push.

Pour reproduire le bug:

  1. Créez un nouveau storyboard qui utilise des classes de taille.
  2. Créez deux contrôleurs de vue (pas de contrôleurs de navigation).
  3. Faire en sorte que le premier contrôleur de vue affiche le deuxième contrôleur de vue via un Show (par exemple, Push) lié à un bouton, par exemple.
  4. Dans le code, affichez le premier contrôleur de vue, mais intégrez-le dans un contrôleur de navigation via la initWithRootViewController:méthode.
  5. Exécutez l'application sur iOS 7.
  6. Appuyez sur le bouton qui doit effectuer la poussée.
  7. Vous obtiendrez une transition modale au lieu d'un push sur iOS 7. Sur iOS 8, vous obtiendrez le bon comportement push.

entrez la description de l'image ici

Pour corriger le bogue:

  1. Ajoutez un contrôleur de navigation au storyboard et définissez le premier contrôleur de vue comme contrôleur de vue racine. (Remarque: l'ajout du second en tant que contrôleur de vue racine ne corrigera PAS ce bogue.)
  2. Donnez-lui un identifiant indésirable pour supprimer l'avertissement indiquant que le contrôleur de navigation est inaccessible et pour vous documenter qu'il existe uniquement comme solution de contournement. (par exemple workaround for show segues in iOS 7).

entrez la description de l'image ici

Remarquez comment le contrôleur de navigation a été ajouté dans la deuxième image, et comment il n'a pas de flèches entrantes (c'est-à-dire qu'il n'y a aucun moyen de l'instancier autrement qu'en utilisant son identifiant de contrôleur de vue).

Sensé
la source
1
Merci, l'astuce avec le NavigationController l'a fait pour moi lorsque je change la racine NavigationControllers ViewController-Stack
Peter Pint
1
Meilleure solution. Merci
Илья Голованов
13

Je sais que je suis en retard mais je voulais partager ce que j'ai appris. Il s'agit en fait d'un bug et est toujours présent aujourd'hui (18/12/2014).

J'ai écrit un article à ce sujet ici .

Il est facilement reproductible; sur iOS8 fonctionnera très bien et même dans iOS7.x tant que vous ne poussez pas un contrôleur de vue par programme dans la pile avant d'appeler le Showsegue.

Si vous poussez uniquement vers la pile en utilisant des connexions de storyboard, cela fonctionnera; mais apparemment, si vous poussez via le code, la navigationControllerpropriété du push UIViewControllersera nilet quand vous appelezShow il supposera que c'est un modal car il n'y a pas de navigation pour contrôler la pile.

La seule solution de contournement jusqu'à présent est de ne pas pousser via le code (pas faisable) ou d'utiliser le désormais obsolète Push .

J'ai déposé un radar (lien sur l'article). N'hésitez pas à déposer des doublons dans l'espoir qu'Apple corrige ce problème.

Esttorhe
la source
3
C'était exactement mon problème, merci! l'utilisation de push obsolète semble être la moindre solution maléfique dans ce cas.
Moshe Gottlieb
Une autre solution de contournement consiste à ajouter un contrôleur de navigation (inutilisé) au storyboard. Voir stackoverflow.com/questions/24184003/…
Senseful
Non! Cela se passe ici et la cause n'est pas une poussée programmatique. Dans mon cas , j'effectue une séquence, Showpuis sur la deuxième Showséquence, elle est présentée modalement, Solution?
Frade
@Frade pouvez-vous créer un lien vers un dépôt github où cela est reproductible? Utilisez-vous quelle version d'iOS?
esttorhe le
projet privé .. Cela se produit lorsque vous essayez d'effectuer une (seconde) Showd'un viewController sur iOS 7
Frade
2

J'ai eu le même problème avec les segues dans Xcode 7 et iOS 7.1.2. Afficher les segues (nouvelle fonctionnalité d'iOS 8) fonctionne comme les segues modales dans iOS 7 et ne vous permet pas de pousser vos contrôleurs de vue dans la pile du contrôleur de navigation lorsque vous définissez le type de segue avec Xcode dans votre Storyboard. C'est pourquoi votre self.navigationController renverra nil, car le contrôleur de vue n'a pas été poussé vers la pile et vous ne pouvez pas le faire apparaître.

Je ne comprends pas pourquoi Apple n'a ajouté aucune notification pour ce cas dans Xcode lorsque vous avez besoin que votre application fonctionne sur iOS 7. Ils disent que la méthode Push est obsolète, mais Show ne fonctionne pas correctement avec iOS 7.

Qu'ai-je fait pour résoudre le problème:

J'ai créé la classe MYShowSegue avec .h

#import <UIKit/UIKit.h>

@interface MYShowSegue : UIStoryboardSegue

@end

Et fichier .m avec une seule méthode perform :

#import "MYShowSegue.h"

@implementation MYShowSegue

- (void) perform {

    if ([[[self sourceViewController] navigationController] respondsToSelector:@selector(showViewController:sender:)]) {

        id sender = nil;
        [[[self sourceViewController] navigationController] showViewController:[self destinationViewController] sender:sender];
    }else{

        [[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:YES];
    }
}

@end

Ensuite, vous devez définir un type personnalisé pour chaque suite dans votre Storyboard et sélectionner une nouvelle classe pour cela, dans mon cas, c'était MYShowSegue.

Exemple de segment personnalisé

Cette solution vous aidera à obtenir un support complet de vos applications iOS 7, elles utiliseront la méthode pushViewController pour pousser vos vues et pour iOS 8,9 etc. votre segue fonctionnera avec la nouvelle méthode (iOS 8) showViewController

N'oubliez pas de faire de même avec toutes vos segues dans votre Storyboard.

Igor Tikhonov
la source
Belle solution - a fonctionné pour moi (au lieu d'ajouter un contrôleur de navigation "inutilisé" ...
Laurenz Glück
1

Cela se produit toujours dans iOS 10.x

La suppression et la réinstallation de segues n'ont rien résolu pour moi:

Problème: la fonctionnalité requise était de 7 segues qui ne fonctionnent que comme un «push» (en fait un show Detail) mais en fait seule la première segue que j'ai ajoutée pousserait, les autres se comporteraient toutes de manière modale. Ceci malgré qu'Interface Builder décrive chacun des segments de manière identique.

Solution: j'ai dû ajouter l'action aux 6 segues qui ne l'avaient pas.

XML du storyboard original

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" id="3NK-93-wTy"/>
</connections>

J'ai changé cela en ajoutant showViewController: sender

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" action="showViewController:sender:" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" action="showViewController:sender:" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" action="showViewController:sender:" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" action="showViewController:sender:" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" action="showViewController:sender:" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" action="showViewController:sender:" id="3NK-93-wTy"/>
</connections>
Damo
la source