ChatGPT解决这个技术问题 Extra ChatGPT

Adaptive segue in storyboard Xcode 6. Is push deprecated?

https://i.stack.imgur.com/hdOls.png

https://i.stack.imgur.com/IkDXR.png

instead old:

https://i.stack.imgur.com/le75A.png

Now we have "show" and "present modally" instead of "push" and "modal". The old options are marked as deprecated. I've chosen "show" option, because in segue settings it called "show (e.g. push)

https://i.stack.imgur.com/3uPOx.png

But it doesn't make push. Segue animation looks like slide from the bottom (modal) and navigation bar disappears.

Question is: How can I make "show" work like push? Is it possible or should I use "push (deprecated)" instead? Where can I find any information about new types of segue? The only thing that I've found in iOS8 developer library is Storyboards Help You Design Your User Interface but there is no information about "show" segue.

UPDATE

I tried to create new project and "show" is really works like "push". I think the issue in my project can be because I reuse navigation controller with code like this, but I don't know how to fix it.

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];
    };
    
}

https://i.stack.imgur.com/Tzo4p.png

UPDATE 2:

I seems to be only iOS 7, iOS 7.1 issue.


C
Caleb

Yes, use ‘Show’ instead of ‘Push’

How can I make "show" work like push? Is it possible or should I use "push (depricated)" instead?

It should; it does for me. I am using Xcode 6 beta 2 and to test I used the single view template (calling the pre made view controller in IB ‘VC_A’). I then added another view controller (‘VC_B’). I then added a button on VC_A to show VC_B and another from VC_B back to VC_A. When I add a navigation controller as the initial view controller in the storyboard and make VC_A the rootViewController, both ‘push’ and ‘show’ have the same effect. If I don’t have an initial navigation controller and I use ‘show’ I get what you described in that the VC_B does a slide up from bottom. If I try to ‘push’ I get a crash since in order to do push I must have navigation controller. So it would seem that ‘show’ will do a push in the case where a navigation controller is provided and do a present with a modal transition style if a navigation controller is not present.

Where can I find any information about new types of segue?

So I found some information in the ‘What’s New in Interface Builder’ session here. If you look at the slides you will see one slide (41) mention the change. When watching that session video you can skip to minute 38:00 where they start talking about adaptive segues. They do explain that the ‘show’ adaptive segue, for example, takes the context in account when deciding how to do the presentation of a new view controller.


Thank you for your answer. I tried to create new project and "show" is really works like push with navigation controller. In my project I have complicated structure with the sidebar from this lesson appcoda.com/ios-programming-sidebar-navigation-menu and push works, show doesn't. May be the reason is I reuse navigation controller. I've updated my question with the reuse code.
So the first thing that I see when looking at your update is that you are using expecting custom segue: 'SWRevealViewControllerSegue' so yeah it probably doesn't make sense to use 'show' or 'push' in your case since those are built in segues whereas you are wanting to run your own custom code. When I download the sample project, it even shows to the selection of 'custom' on the segues in the storyboard file.
I didn't mean this segue. I was talking about creating new UIViewController next to "MainViewController" (it has Navigation Controller, and my "update" only shows how do I get it there) and attempts to push new View into MainViewController. Storyboard Screenshot I will be grateful if you enable "use size classes" in sample project, create NewViewController and try make segue between MainViewController and NewViewController by "show". You will see what am I talking about.
Did that just now and at least for me "show" operated just like "push".
You can work around the bug by making sure that all ways into your view controller have a UINavigationController at their root. Even if that means putting a UINavigationController into your storyboard that will never be accessed. It looks like the wiring is used to infer behavior.
C
Community

There is already an accepted answer, but I wanted to give a bit more information, possibly information that was not available before.

As was mentioned previously, the "push" and "modal" segues were deprecated, and have been replaced by "show" and "present modally" respectively. According to Apple's documentation, the new segues have been further divided into segues that adapt to size classes. The older ones should only be used to support iOS versions older than iOS 8.

The document in the following link explains that and the description of all the available segues, old and new.

Adding a Segue Between Scenes in a Storyboard

In case the URL changes in the future, this is the explanation given for each new segue:

Show Present the content in the detail or master area depending on the content of the screen. If the app is displaying a master and detail view, the content is pushed onto the detail area. If the app is only displaying the master or the detail, the content is pushed on top of the current view controller stack. Show Detail Present the content in the detail area. If the app is displaying a master and detail view, the new content replaces the current detail. If the app is only displaying the master or the detail, the content replaces the top of the current view controller stack. Present Modally Present the content modally. There are options to choose a presentation style (UIModalPresentationStyle) and a transition style (UIModalTransitionStyle). Present as Popover Present the content as a popover anchored to an existing view. There is an option to specify the possible directions of the arrow shown on one edge of the popover view (UIPopoverArrowDirection). There is also an option to specify the anchor view.


T
Tommie C.

tldr; Delete the Segue that is not pushing correctly and recreate it in the storyboard by dragging from a UIView/UIControl to the target view controller.

There is nothing wrong with the other answers but this one explains what is happening, how you can verify that it is happening and how to mitigate the issue in the future.

Background

In my case, none of my Show Segues were working even though I already had a UINavigationController as my initial view controller (with my content UIViewController as it's root).

Why and How the Show Segue Breaks

The Show segue breaks when it has an action associated with the segue within the storyboard's source xml. A typical scenario causing this might be if you have redefined a segue from a manual segue previously called in code. This leaves the following bits in the storyboard xml.

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

Nota Bene To view storyboard as xml; Right click the storyboard file and choose Open as > Source Code. To revert use Open as > Interface Builder - Storyboard

To accommodate any custom actions when using the segue from the storyboard one can just tap into prepareForSegue and intercept the destination view controller and call any methods from that location. In any case, the side effect for this little bug (the bug is the fact that when you redefine the segue it is not properly setup in xml ~ i.e. the action remains even after your change the segue to one that operates from a UIView (or UIControl) to a target view controller).

Unfortunately the most direct solution fails. So just removing the xml attribute for the action from within the Storyboard will NOT fix the problem. Instead one has to simply delete and recreate the segue in the storyboard.

When recreated the storyboard xml will no longer have an action associated with the particular segue and the Show will execute as a Push.

Sample Xml for correct Show Segue

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

Mitigation

To prevent recurrence one just needs to stick to non-manual storyboard segues if possible by using the prepareForSegue to add required actions based on destination view controller. Or if you must to mix and match, take the precaution to verify that your Show segues do not have any actions attached in the storyboard xml. If you are dealing with older projects then you should give special attention to the Storyboard source code as I've discovered a few issues.


After hours, this saved me probably some other hours. Here is, what I would suggest based on the above: Open the storyboard as Source Code, search for kind="show" and look if the line contains something like action="showDetailViewController:sender:", if so, delete everything from action= until the closing ". I have a real huge storyboard and the affected seque did't contain this action parameter but another unrelated line did. Once I deleted the action, all adaptive seques worked again as expected. Just deleting the affected seque didn't work.
This saved me as well.
Deleting the action attribute in the XML worked for my friend.
saved me as well
Deleted the action attribute in the xml file, and voila, it works. Would have never found the issue without this post.
C
Community

As Scott Robertson commented here, this looks like a bug in iOS 7.

It appears that in iOS 8 the transition is inferred at runtime (correct behavior), while in iOS 7 the transition is inferred at design time (buggy behavior).

The simplest workaround is to add an unused navigation controller to the storyboard and link it up so that the view controller in question is part of this navigation controller. You don't actually have to instantiate the navigation controller, you just need the buggy view controller to know it is embedded in a navigation controller.

Note: Simulating a navigation bar is not sufficient for these purposes; you must actually have a navigation controller in its push stack.

To reproduce the bug:

Create a new storyboard that uses size classes. Create a two view controllers (no navigation controllers). Make the first view controller show the second view controller via a Show (e.g. Push) segue linked to a button, for example. In code, show the first view controller, but embed it in a navigation controller via the initWithRootViewController: method. Run the app on iOS 7. Tap the button that should perform the push. You will get a modal transition instead of a push on iOS 7. On iOS 8 you will get the correct, push behavior.

https://i.stack.imgur.com/l2nxx.png

To fix the bug:

Add a navigation controller to the storyboard and set the first view controller to be the root view controller. (Note: adding the second as the root view controller will NOT fix this bug.) Give it a junk identifier to suppress the warning about the navigation controller being inaccessible, and to document to yourself that it exists solely as a workaround. (e.g. workaround for show segues in iOS 7).

https://i.stack.imgur.com/QAAyl.png

Notice how the navigation controller was added in the second picture, and how it doesn't have any incoming arrows (i.e. there is no way to instantiate it other than using its view controller identifier).


Thanks, the trick with the NavigationController did it for me when im Swapping the root NavigationControllers ViewController-Stack
Best solution. Thanks
e
esttorhe

I know I'm late to this but I wanted to share what I learned. This is in fact a bug and is still present today (2014-12-18).

I wrote an article about this here.

It is easily reproducible; on iOS8 will work just fine and even in iOS7.x as long as you don't push a view controller programmatically into the stack before calling the Show segue.

If you only push to the stack using storyboard connections it will work; but apparently if you push via code somehow the navigationController property of the pushed UIViewController will be nil and when you call Show it will assume its a modal because there's no navigation to control the stack.

Only workaround so far is either not push via code (not feasible) or use the now deprecated Push.

I filed a radar (link on the article). Feel free to file duplicates with the hopes of Apple fixing this issue.


This was exactly my issue, thanks! using deprecated push seems to be the lesser evil solution in this case.
Another workaround is to add an (unused) navigation controller to the storyboard. See stackoverflow.com/questions/24184003/…
Nop! Its happening here and the cause is not a programmatically push. In my case I perform a Show segue, then on the second Show segue it is presented modally, Solution?
@Frade can you link to a github repo where this is reproducible? Are you running on which version of iOS?
private project.. It happen when trying to perform a (second) Show of a viewController on iOS 7
I
Igor Tikhonov

I had the same issue with segues in Xcode 7 and iOS 7.1.2. Show segues (new feature from iOS 8) works like modal segues in iOS 7 and do not allow you to push your View Controllers into the Navigation Controller stack when you define segue type with Xcode in your Storyboard. That's why your self.navigationController will return nil, because the View Controller was not pushed to the stack and you can not pop it.

I don't understand why Apple did not add any notifications for this case in Xcode when you need your app to work on iOS 7. They say that Push method is Deprecated, but Show does not work correctly with iOS 7.

What have i did to resolve the issue:

I have created MYShowSegue class with .h

#import <UIKit/UIKit.h>

@interface MYShowSegue : UIStoryboardSegue

@end

And .m file with only one perform method:

#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

Than you need to set a Custom type for each segue in your Storyboard and select a new class for it, in my case it was MYShowSegue.

Custom Segue Example

This solution will help you to get a full support of your iOS 7 apps, they will use pushViewController method to push your Views and for iOS 8,9 etc. your segue will work with new (iOS 8) method showViewController

Do not forget to do the same with all your segues in your Storyboard.


Nice solution - worked for me (instead of adding a "unused" navigation controller...
D
Damo

This is still happening in iOS 10.x

Deleting and re-instating segues did not solve anything for me:

Problem: Requred functionality was 7 segues which only operate as a 'push' (actually a show Detail) but in fact only the first segue I added would push, the others would all behave modally. This is despite Interface Builder describing each of the segues identically.

Solution: I had to add the action to the 6 segues which didn't have it.

Original Storyboard XML

<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>

I changed this by adding 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>