I've been looking through some very helpful examples on how implement custom transitions between segues (e.g this one).
But I just can't figure out how to do this with UISplitViewController.
Can I get any hint/tips?
I know that in the MasterViewController you can prepareForSegue when showing a new DetailedViewController. But setting the transitioningDelegate on the destinationViewController does not seem to work at all.
I also tried to set the MasterViewControlleras the NavigationViewControllerDelegate and return the UIViewControllerAnimatedTransitioning, but that didn't work either (as expected, but I wanted to try).
Related
I recently changed my app structure to include a UINavigationController as base for my hierarchy and I had its root viewController implement the UINavigationControllerDelegate protocol in order to implement custom segues.
My viewController implements navigationController:animationControllerForOperation:fromViewController:toViewController:.
My problem is two-fold:
The navigationController.delegate methods are not being called.
The navigationBar is not called in the views being pushed via storyboardSegues of type show.
The prepareForSegue:sender: function is being called.
This is my UI:
Turns out that UIStoryboardSegues I added before I added the UINavigationController to my hierarchy are still interpreted as modal segues. Probably this is set during creation.
The problem was solved by deleting and re-adding the segues in question, with the relevant information (identifier, class...) transferred to the new instance.
If you have the same problem, when you set Top Par to inferred in your segued viewController you will see no navigationBar showing.
After replacing the segues the Top Bar showed again as normal.
Edit:
I posted the question together with this answer, since there was no post on SO covering this issue. self-answer
I've been struggling on this for a while now, but I wasn't able to find a solution:
I've got an iOS 9 app that supports all device families, uses size classes and is programmed with Swift 2.0.
I'm using a UISplitViewController and everything works as I want, except in a collapsed environment (e.g. on an iPhone).
The Master-ViewController is a UITableViewController that triggers a replace segue when a cell is selected. In a collapsed environment this means, that the detailViewcontroller gets pushed onto the screen. The UISplitViewController visually behaves kind of like a UINavigationController.
However, when I dismiss the detailViewController with the back button or the swipe gesture it does not get deallocated until the a new replace segue is triggered in the Master-ViewController.
I assume that this is kind of a feature of UISplitViewController, since it was originally designed to show both contents next to each other. Nevertheless, in a collapsed environment I would like my UISplitViewController to behave like a simple UINavigationController, which deallocates the previously pushed detailviewController when popped.
I've been trying to manually change the splitViewController's viewControllers attribute after the detailViewController is popped:
if let firstVc = self.splitViewController?.viewControllers.first {
self.splitViewController?.viewControllers = [firstVc]
}
But that does not help. Simply replacing the detailViewController with an empty "Dummy"-ViewController doesn't work neither, since it automatically animates the transition.
Playing around with the UISplitViewControllerDelegate didn't help me neither...
Is there a solution for this (maybe simple? :)), that I'm too blind to see?
This used to be pretty straightforward in the good ol' xib days. I'm getting into custom transitions in iOS 7. The root view controller for the my app is a UINavigationController. To get custom transitions to work, I need to set the delegate on my main UINavigationController.
I'd like to do this as soon as possible after load time. I tried doing it in application:didFinishLaunchingWithOptions:, but self.window.rootViewController is returning nil at that point.
So I guess my question is: when is the earliest I can set the delegate?
I suppose I can do it in viewDidLoad of my main view controller (the Navigation controller's root view controller), but that seems like the wrong place design-wise.
I have an app created from Xcode 4.5's boilerplate Master-Detail Application with CoreData, StoryBoards and ARC turned-on that is not calling prepareForSegue. CoreData isn't currently being used, but it will be to cache XML responses. performSegueWithIdentifier works, but prepareForSegue isn't and I'm having troubles passing/access data from the MasterViewController to/in the detailViewController created by performSegueWithIdentifier.
My basic set-up is similar to what's discussed in the thread: Storyboards and UISplitViewControllers. There's an image of a storyboard on page three that's very similar to my set-up (I don't have enough rep to post images).
In a nutshell:
I create a standard splitView arrangement
The MasterViewController builds the main table
Each cell corresponds to a URL that returns XML data that determines what's in the detailView
The fetched XML is parsed using a NSXMLParser operation/class
The fetched XML determines which detail view is needed and the MasterViewController calls the appropriate 'replace' segue (via performSegueWithIdentifier) to kick-off the corresponding detailViewController to display the fetched XML
The problem that I'm having is that prepareForSegue isn't being called, so I can't pass the fetched XML to the detailViewController.
What I need is one of the following:
prepareForSegue to be executed
a way to know segue.destinationViewController inside handleLoadedResponse:notif
a way to get access to the "currentResponse" variable in the MasterViewController from inside the viewDidLoad method of the detailViewControllers
a way to find the MasterViewController via its StoryBoardID
What I've tried:
Putting NSLog() statements in each viewController's prepareForSegue -- none of them are called
Digging through the self.parentViewController chain in the detailViewController to find the MasterViewController that called performSegueWithIdentifier -- I can't find the class variable I'm looking for
Read pretty much every "prepareForSegue not called" post I could find -- They all seem due to some coding/storyboard error that I don't see in my code/storyboard
Could the problem be that I'm calling:
[self.navigationController performSegueWithIdentifier:#"theDesiredSegue" sender:self];
from inside the handleLoadedResponse:notif call-back and the app is trying to call prepareForSegue in my parsing object?
TIA
Ray
Well, chalk this up to staring at the code too long and/or newbie-ness.
After triple-checking everything that I though was obvious, I thought the only thing left was that the segue code didn't behave correctly inside the NSXMLParser call-back, so I switched the handleLoadedResponse:notif routine to store the parsed data and send-out notifications.
While debugging those changes, I realized that my segues were attached to the wrong object. They were actually attached to the navigationController and not my viewController. Visually, things looked like the story board on page three of RWForums: Storyboards and UISplitViewControllers, but they really weren't. The end result being that even though it seemed like my code was calling performSegueWithIdentifier and that it's prepareForSegue method should have been called, it was actually calling the navigationController's segue, so the navigationController's inherited prepareForSegue was being called.
Recommendation: Make sure you re-re-re-check all the connections in the StoryBoard Editor with the Document Outline open.
Ray
I'm moving my App to Storyboards and, so far, so good.
However, I've found something that I don't really understand and worries me. I would appreciate if someone can provide some insight on this.
My app uses a normal Navigation Controller. For moving "forward" to new View Controllers, I'm using custom segues; no problems there. However, there's a point in the App where I want to move back to the beginning of the Navigation Stack. I have also configured that "navigation" using a custom segue, for that, I created the segue in Interface Builder by dragging the last view controller to the first one (that already looks weird to me), and I've implemented the custom segue perform method in the following way:
-(void)perform
{
UIViewController *src = (UIViewController *)self.sourceViewController;
UIViewController *dest = (UIViewController *)self.destinationViewController;
[src.navigationController popToRootViewControllerAnimated:NO];
// Custom animation code here
}
... It works great. However, I don't understand why it works. In my mind, the custom segue should be instantiating a new instance of my first view controller and assign it as "dest", but it looks like the segue is smart enough to realize I want to navigate to a previous, existent, instance of a View Controller and, instead of creating a new instance, it assigns to "dest" the existing one.
Does anybody know if using segues in this way is ok? Is it possible that it works by chance but might stop working in the future? Am I wasting memory in anyway as the segue is instantiating a View Controller I'm not going to use?
Thanks a lot in advance!
Am I wasting memory in anyway as the segue is instantiating a View
Controller I'm not going to use?
Yes sir! By using a segue, you effectively allocate a new view controller as it's needed to set the DestinationController property for your custom segue. Test by yourself : add a static counter into your root controller, increment it each time this class is initialized and display it in your view : you'll see it getting incremented every time you pop to root using this trick.
Does anybody know if using segues in this way is ok?
As long as you're effectively wasting memory, no!
There's at least one solution to this problem : release the DestinationController of the segue in your (void)perform implentation. This is really quick to implement, but kinda ugly since you allocate and immediately release your view controller every time... even if it's better than just leaking it, it's not what I'd call a good practice!
To my mind, a better way to achieve what you want would be to not use a segue for that transition, just to use a button or whatever and call popToRootViewController:animated when getting a touch on this button.
Is it possible that it works by chance but might stop working in the
future?
For both the first solution I suggested and the way you're currently doing it, I see absolutely no reason : these are not complicated tweaks, just 'bad-implemented' standard navigation. The second solution is perfectly normal so no worries.