One segue to rule them all - ios

I have 4 ViewControllers in my storyboard. I want all of them to be able to access my "Settings" ViewController by performSegue.
Is it possible to have ONE segue to perform this, instead of ctrl + drag from each and every ViewController to my "Settings" ViewController?

No its not possible with a single segue. You need 4 different segues from 4 different ViewControllers. But you can do this programatically.
Make an extension for UIVIewController
extension UIViewController
{
func showSettingsScreen()
{
let storyBoard = UIStoryboard(name: "YourStoryBoardName", bundle:nil)
let settingsScreen = storyBoard.instantiateViewControllerWithIdentifier("YourSettingsViewControllerID")
self.navigationController?.pushViewController(settingsScreen, animated: true)
}
}
Now you can call showSettingsScreen() from any of your view controllers(Make sure this view controller has a navigation controller).

You cannot do that. A segue has only one source and one destination. You could programatically instantiate your Settings ViewController and display it either by using push or by using present. What you should think of though is why do you have to go to settings from so many places. It might be a sign of bad design and duplicate code. Usually applications have only one such button/action that can be accessed from multiple screens (by using some kind of container view implementation) or from only one screen.

I really dont think so there is a way to do so. U ought to connect ur SettingsViewController to all of your 4 View Controllers, add segue , and define a segue identifier which is used in
prepareForSegue:sender:
or
shouldPerformSegueWithIdentifier:sender:
methods. U can access segues through these identifiers. If u find "ctrl + drag from each and every ViewController to "Settings" ViewController " tasky you can opt for Navigation Controller as well. U just have to embed Navigation Controller in your storyboard and define Storyboard Id for every View Controller and you are done. Just use storyboard id of view controller to be instantiated and u good to go.
ViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:vc animated:YES];
Apart for assigning storyboard id you dont have to worry about storyboard ,No ctrl+drag thing.
I thought of one more elegant solution i.e. using Container View. You can take button to switch, SettingsViewController as common, in your Container View Controller while displaying every ViewController.
happy Coding..

There is one way to do this. Create a root view controller and matching view which contains a single embedded view. Add your segue to this root controller. Then in your app you switch in the other view controllers using standard child container techniques. This is pretty much the concept that UINavigationControllers use.
One advantage from this is that if you want to have common elements which are visible to all controllers then you can add them to your root controller.
But it all depends on what you are trying to achieve.

Related

Storyboard segues and receiving memory warning

I am developing an application with iOS 9 based SDK , this is my first time I am working with Storyboards , I have 20 view controllers, each scene has Next / Previous buttons to go back and forward . I have a huge problem with going forward !. If I move from scene 1 to for example to scene 15 I received memory warning and then application crashes . I have searched and it seems there is method called unwind segue but it seems this is for going back ! it's something like dissMiss method .
I connect each scene with line in Interface Builder :
Here is segue's setting :
I would be grateful if you help me out .
EDITED :
I tried to present a view controller programmatically but result was the same ! .
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
WhatIsDino *vc = (WhatIsDino*)[mainStoryboard instantiateViewControllerWithIdentifier:#"WID"];
[self presentViewController:vc animated:YES completion:nil];
Seems like it's a problem of wrong approach, and not the storyboard.
Let me guess, since before storyboard you used to change your app's rootViewController to the next/previous screen once you tap on the arrow button. So previous screen are released and deallocated from memory once you set a new rootViewController.
And now you're presenting every next view controller modally, which involved creating new UIWindow and loads all the hierarchy of you screen and keeps previous underneath the new one so it holds the memory and you're getting out of memory crash.
Well, you can do rootViewController approach with a storyboard too since it's just another way to manage your screens while development. Storyboard offers additional features like segues, static table view cells, general tint color and so on. [UIStoryboard -instantiateViewControllerWithIdentifier:] is the method you might find interesting.
But I'd rather recommend you to check out the UIPageViewController, it's like a container for the screens. Unfortunately, it cannot have the segues to your scenes (because of the special way segues work) so you have to use -instantiateViewControllerWithIdentifier: method anyway. You can treat inner view controllers of UIPageViewController as you do with rootViewController before.
You can also navigate without segue and Its easy way I think.
If you want to navigate from Class1 to Class 2 then follow these steps.
1) In Class 1, Import Class2.
2) In your button Action, Write this code.
Class2 *next = [self.storyboard instantiateViewControllerWithIdentifier:#"Class2 Identifier name"];
[self.navigationController pushViewController:next animated:YES];
Do not forget to give Identifier name in story board that is "Storyboard ID" in Attribute inspector of particular class.
No need to add Segue,Your storyboard would look clean.
The problem is that you are adding view controller after view controller with modal presentation. That causes each view controller to be added on top of the previous one, and all of them accumulate, using more and more memory.
Using a navigation controller and a push also piles the view controllers on top of each other.
You will have this problem if you use storyboards, nibs, or create the view controllers manually.
If you have a design where the user can move through a large series of view controllers then you probably want to dismiss the previous one before pushing/presenting a new one.
You can probably dismiss the previous view controller without animation and then present the new view controller each time you want to display a new one and avoid the memory issue. i'd have to experiment with it to get the effect I was after, but that's what I would suggest.

Segue to a viewcontroller in another storyboard without a navigationcontroller

I want to move to another viewcontroller in another storyboard and the view controller im in is not embedded in a navigationctroller.
Normally i would just instantiate the viewcontroller and push it to the navigationcontroller stack but since this is not possible i dont know what to do, and I cant seem to find any help on this.
Any suggestions?
It depends on what you're trying to achieve in the app, but a few options are: present it as a modal controller, create your own custom type of segue, replace the root controller in the app's window....

How to perform custom segue across two storyboards?

so I inherited an old project at work that's broken up into a ton of different storyboards. While this hasn't really been too much of a hassle, the client now wants a custom segue animation that goes from a View Controller on Storyboard A to a View Controller on Storyboard B and I can't figure it out for the life of me.
I have the animation worked out if the views are on the same Storyboard, but I can't get it hooked up to a transition to another storyboard.
You can't do this without using a trick, because you can't connect a segue between storyboards. You can instantiate the controller manually in the other storyboard, then do whatever custom animation you want to present or push it in code. Since the main reason for using a segue (as opposed to transitioning to the new controller in code) is that you can see the connections between your controllers in the storyboard, there's not much reason to use a segue in your case.
If you really insist on using a segue, then you need to put a "dummy" controller in your first storyboard that you connect a custom segue to. The code in that segue switches out the dummy controller for the real controller you want to segue to in the other storyboard. You can find a reference to that technique here, http://spin.atomicobject.com/2014/03/06/multiple-ios-storyboards/.
Find below code for accessing another storyboard view:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"storyboard_A_view_identifier"]) {
UIStoryboard *storyBoardB = [UIStoryboard storyboardWithName:#"storyBoardB" bundle:nil];
UIViewController *anotherViewController = [storyBoardB instantiateViewControllerWithIdentifier:#"storyboard_B_view_identifier"];
// use anotherViewController and perform custom animation on it
}
}

Creating a central log out view controller in storyboard

I am working with Parse, and one thing I have implemented in my app is their built in PFLogInViewController. This controller will be presented at two times in the application - when the app first starts and the user is not logged in, and when the user taps the "Log out" button of my application (logging out takes them back to the PFLogInViewController, as you are required to sign in to use the app). I would like to set this up using Storyboard, as that is how the rest of my app is laid out. How could I set up a central view controller (a PFLogInViewController) that is accessed at these two times? I have already Subclassed PFLogInViewController and set it up, I just need advice on how to place it in Storyboard and how to connect it to my views. To make this question help as many people as possible, the general theme of my question is how does one establish a central Login/ViewController that can be accessed at different points in the application using Storyboard. Attached is the basic idea of what I'm trying to accomplish. I haven't been able to successfully segue to the initial TabBarController, and I'm not sure how I should make the LoginController the initial ViewController if I can't segue. I am programming in Swift, if it matters.
There are a few ways to do this depending upon your application. One way is drop a UIViewController onto the storyboard, but don't wire it up to anything (no segue). Create a storyboard id for it such as "MyLoginVC". Do the necessary subclassing of UIViewController and attach the class to your VC. Then, when you want to display the VC simply do the following or wire this up to your logout button
id destinationVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[self.navigationController pushViewController:destinationVC animated:YES];
In addition, if you want to show the login VC as the very first VC when you launch your app, then perhaps in your AppDelegate
// Load Root view controller
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.rootVC = [storyboard instantiateInitialViewController];
self.window.rootViewController = _rootVC;
[self.window makeKeyAndVisible];
// Load Login view controller
id initialVC = [storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[initialVC setModalPresentationStyle:UIModalPresentationFullScreen];
[_rootVC presentModalViewController:initialVC animated:NO];
When you finish with your login VC (i.e. successful login) then within login VC
[self dismissViewControllerAnimated:NO completion:nil];
and alternatively instantiate your first VC with something similar to the following from within login VC. Note, since you loaded the root VC above first, it is already there with the login VC sitting over it. When you dismiss login VC, the underlying root VC should be ready to rock and roll. Otherwise you can do the following:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
RootTabBarController *tbController = (RootTabBarController *)[self.storyboard instantiateViewControllerWithIdentifier:#"rootTabBarController"];
[self presentViewController:tbController animated:YES completion:NULL];
}
I think what you want is an unwind segue. Here are the instructions I follow for an unwind segue: https://github.com/bradley/iOSUnwindSegueProgramatically
If the link dies, here is what it said:
In your storyboard create two view controllers.
Subclass UIViewController twice, once for each of the view controllers in your storyboard.
Connect these view controllers to the view controllers in your storyboard.
Make a segue between the first view controller and the second by control+dragging from the first to the second.
Click on the segue you created and give it an identifier in the attributes inspector.
Make a button on the first view controller and link it to an IBAction in its UIViewController subclass.
When this button is pressed, the second storyboard should appear. To make this happen (we are doing it programatically) put the following into the implementation of the action you just created:
[self performSegueWithIdentifier:#"nameOfTheSegueBetweenOneAndTwo" sender:self];
Create a second method in the implemention of the first view controller with the following:
- (IBAction)returnToStepOne:(UIStoryboardSegue *)segue {
NSLog(#"And now we are back.");
}
This method will work to unwind any view controller back to this view controller. Notice that we implement the method in the view controller we wish to return to.
Go back to the storyboard. Focus in on the second view controller. If it is active, you should see a dark bar beneath it with 3 symbols on it. One of these is orange and when hovered over will show the name of the UIViewController subclass that this view controller represents. Control drag from this symbol woth the green symbol that means 'Exit'. You should see all available segue unwinds, which XCode automatically enumerates when you create segue unwind implementations inside UIViewController subclasses that you have shown on your stroryboard. Hence, you should see the segue 'returnToStepOne' as an option. Select it.
In your storyboard's document outline, find the section for the second view controller. You should see an item listed below it with a grey symbol that says something like "Unwind segue from ... to Exit." Click on this item.
Important and easily missed step follows!
On the right side of your storyboard, in the attributes inspector, you should see two fields. One for 'Identifier' and one for 'Action'. In most cases, the 'Action' field will have the text 'returnToStepOne:', which is what we want, but the 'Identifier' field will be blank. Fill this field with the text: 'returnToStepOne' (note that we leave out the colon).
Create a button on the second view controller and link it to an IBAction in its UIViewController subclass.
In the implementation for the method you just created, put the following code:
[self performSegueWithIdentifier:#"returnToStepOne" sender:self];
Run the application. You should now be able to unwind from the second view controller to the first.

ECSlidingViewController with Push and Unwind Segue

I am using ECSlidingViewController with storyboards. ECSlidingVC is my root (starting) controller. My left menu is a TableView with static cells, and my TopViewController is a navigation controller. I want to have a single NavigationController for all my app.
From my left menu i cant use push or unwind segues, i understand that part though. i can only use ECSlidingSegue which changes topviewController of ECSlidingVC and which destroys my navigation controller and it's stack.
i want to be able to go back from a menu item VC to previous VC in my main nav controller. lets say basically i want ECSlidingVC to not change topViewController but push destination viewController to my source.topViewController.navigationController.
Also i need to use unwind segues with my menu items. i need to go back to a VC in my main nav controller.
i inspected ECSlidingSegue source code and all it does is to replace topViewController.
is there a built in method (or segue) in ECSlidingViewController for pushing (or unwinding) VC into source.topViewController.navController or do i need to implement a custom segue myself?
I think the best way to go is for you to implement a custom segue yourself. Something like ECSlidingNavigationSegue, which would look for your topViewController, then check whether it's a UINavigationController and then push the destinationController to it.
It's basically the same perform method as the ECSlidingSegue, but with this feature of pushing a controller to the topViewController instead of replacing it.
Good luck!
In case someone haven't found answer, I did it in this way.
1- #import "UIViewController+ECSlidingViewController.h" to your menuViewController
2- Set stroboardID of your destinationViewController to "someID"
3- When triggering some action, in backend, use this code:
if(self.slidingViewController.currentTopViewPosition == ECSlidingViewControllerTopViewPositionCentered){
[self.slidingViewController anchorTopViewToRightAnimated:YES];
}
else{
self.slidingViewController.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"someID"];
[self.slidingViewController resetTopViewAnimated:YES];
}

Resources