How to manage multi-view apps without segues - ios

I'm working on an app that has about 5-6 different views with inputs and buttons within each view. The user does not necessarily proceed through the views in a set order. One of the views has quite a bit of custom user interaction that subsequently builds out a visual list of text fields and labels. I need the user to be able to leave that view and then return at a later point with the constructed visual in tact.
To avoid having a monolithic view controller, I have each view corresponding to its own view controller and storyboard. As a result, the only main way I can find to navigate between them is via segues. The problem is that, after I dismiss a segue, any interactions or view updates for that view controller are lost when I return to it.
Some of the views only have inputs like a couple text fields but the one view can have upwards of 100+ mixed inputs depending on user interaction. Rather than trying to pass that data around when dismissing and then eventually reload and reconstruct the view, I'm hoping to find a way to hide and show view controllers without losing the visual updates within their views.
Is this possible at all?
Let me know if I'm being too vague and I can try to provide more detail.
Thanks in advance!

You don't have to use segues to display view controllers from storyboards.
You can just load the storyboard, instantiate the view controller and then use it (push or present it or even set it as the key window's root view controller). It's no problem:
// Suppose you have a 'Signup.storyboard' that has an initial viewController defined:
let signupStoryboard = UIStoryboard(name: "Signup", bundle: nil)
if let signupViewController = signupStoryboard.instantiateInitialViewController() {
present(signupViewController, animated: true, completion: nil)
}
If the view controller you want to load is not the initial one, make sure you define a storyboard identifier for it (in the storyboard, e.g. identifier="signup"). Then use:
let signupViewController = signupStoryboard.instantiateViewController(identifier: "signup")
The view controller will be loaded from the respective storyboard and you can use it just as any other view controller.
You can even keep strong references to the controllers and re-use them again after other view controllers were visible in between.

For each of the view controller you need to manage its data source and update in as user changes data in UI. Also you have to store the datasource somewhere i.e. in database, userdefault ,core data etc.
And if user again pushes any view controller load the data from its datasource to see the last changes preserved.
You may use some design and architecture pattern for it.
Here is the link
https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52
Hope this will help.

Related

Navigation Controllers with the same root view

So suppose you need some functionality that requires next storyboard. For example you need to upload different content to view depending on what tab is clicked.
But the problem comes out when you try to use this storyboard. When you switch tabs you getting this behaviour.
But in first tab everything fine. So looks like it doesn't load view second time. Can somebody explain or give a link to the behaviour of navigation controller in this case, because I can't find anything useful in reference. Or how should I correct this behaviour in IB or programatically? Thanks.
a simple work-around is to put a "fake-viewcontroller" as root for the second navigation. On this "fake" controller execute in viewDidLoad a [self performSegueWithIdentifier: #"goToTheControllerHereWeGo" sender: self];
So, as I mentioned in my comment I do think this is a bug but we'll see how Apple responds. But yeah, segues have no love for view controllers that are the root view controllers of multiple navigation controllers. There are a number of workarounds depending on the context under which it comes up.
Best workaround : Share the navigation controllers, not their root view controllers
So for the simple example given above you could do this and everything would be fine:
Other workaround : This one is more applicable to complex storyboards that may have different custom navigation controllers so that sharing the nav controller isn't possible. One hilarious aspect of this issue is that when a view controller has two parent nav controllers in the storyboard, you won't know until runtime which one gets it! And further, on different runs they can switch :P (another reason I think this is a bug).
Sooooo from within prepareForSegue you can check if your navigation controller got unpacked with a rootViewController and, if it didn't, force it in there yourself:
UINavigationController* nc = segue.destinationViewController ;
if (nc.viewControllers.count == 0) {
nc.viewControllers = #[[self.storyboard instantiateViewControllerWithIdentifier:#"MyDetailVC"]];
}
Just provide more explanation beside the comments 'You cannot make a UIViewController as the root view controller of two different Navigation controller'. Suppose you can do so, then the view of the controller will be child view of the two navigation controller's view. It cannot happen as "it" cannot be a child of A but simultaneously a child of B.
On what condition will the tabview items switch , also trigger one of the two separate view controllers? what is the logic? when is it implemented? and no matter whatever the logic maybe, why does a single view controller (let us assume it is being filled up with different data according to the root) has 2 separate roots? we cannot add anything separately from the navigation controller itself,
Navigation controller is the flow that sets the storyboard in motion, but putting a VC as a subview of two different NC just has no point.
Think it of like this,
No additional information is provided by the Navigation controller itself, it just sets things in motion. So why would you want to put a VC as the child of 2root NC.
More easily think it as multiple inheritance, in objc, java its not possible because of the
Diamond problem. look it up and i hope it helps u understand

Embed segue - switching initial UIViewController and the contained UIViewController dynamically

What I need to do is basically build a container(view controller) that can change its child view controller dynamically and also set it's initial view controller dynamically.
I never used the Embed segue before so I thought I'll give it a shot.
However, using it seems to allow me to change the child view controller dynamically using a custom segue between the children view controllers but the initial view controllers seem to be fixed to the one I dragged the segue to in the StoryBoard(The custom segue here would be something alone these lines).
I know I can achieve what i'm looking for by creating x custom segue (where x is the number of children VCs I need) from the container view controller directly to the children and just calling these segues in code based on my needs.
But if that's the only way, what's the reason for using the "Embed" segue, is it only for really simple scenario's ?
An embed segue is not just for really simple scenarii. It can get pretty complicated. A major purpose is to cleanly separate code related to different concerns, that may still coexist on the same screen, into different view controllers. For instance, you could have an authentication controller and a preferences controller, both embedded into a single profile controller.

How to store data after popping a storyboard instantiated view controller to then repush it to the navigation controller stack

I have my UIViewControllers mostly setup using a Storyboard file. In some cases I use the usual pattern of a UINavigationController in combination with UITableViewController to let the user dig into configuration details of the application. Each table view cell causes another view controller to be pushed onto the navigation stack (when the cell is selected) and users can go back to the overview table view controller using the navigation controller's back button.
I have the overview UITableViewController and the detail UIViewControllers set up in the Storyboard, including the connections between them using segues.
Most of it works as expected, when I select a table view cell in the overview the correct detail view controller is pushed onto the navigation stack. But if I then change some views in the detail view controller and go back (possibly because I want to look something up)(thus the detail view controller is popped) and then press the same cell again, the views are reset to their original state and the data I put in is lost.
Of course I could save that data in the overview controller when the detail controller is popped and restore it when it is pushed again, but I wonder whether that is the best way.
In the past, I would have constructed the detail view controller myself and stored it in an instance variable. Then, if I had to push it again, I would push the exact same object (not just an instance of the same class) which would mean that it also saved the state of the view.
But as far as I can tell, using Storyboards, for each segue a new view controller is instantiated, so no data is kept. I also cannot set the destinationViewController property of the segue in prepareforSegue:sender: since it is read-only.
Is there a way to reuse an already created view controller in a segue?
Or is there some other elegant way to store the data to reuse it when the detail controller is pushed again? Ideally something the overview table view controller does not have to know about, since it would have to do store the data for all detail view controller in that case.
I know I could retrieve the view controller from the storyboard, instantiate it myself and push it in tableView:didSelectRowAtIndexPath:, but I like the segues and the overview of the view structure the storyboard provides, so I would like to keep that, if possible.
Update:
I think my description was a bit unclear. I do save the data, already, but currently it is saved in the detail view controller (it's not just "saved" by being in the view, I am not trying to abuse the view to store my data), so going back is an implicit "save my current state in this view" in my case. The problem is, I can't implement that in an easy way without storing the data in the overview controller IN ADDITION to storing it in the detail view controller. And I don't want to store it in the overview controller since it is data that belongs to the detail view controller and should be managed by it.
Of course I could save that data in the overview controller when the detail controller is popped and restore it when it is pushed again, but I wonder whether that is the best way.
I think that is the best way. If the detail view controller is being used to edit the data, generally accepted practice is that the user can only leave it by either saving the data or canceling their changes.

How to find the name of the view controller beneath a popover ios7

This is probably a very simple question but I can't find the answer to it.
I am working on a new project that uses Storyboards for the first time.
I have a number of view controllers that connect the way I want them to.
Each view controller has an info button.
I have one view controller (AboutViewController) that I want to use to display the info for all the view controllers. I am currently calling this via a popover segue from each screen. So I have one destination view controller (AVC) that I am calling from a number of VCs- VC1toAVC, VC2toAVC, VC3toAVC etc. I want two textfields in AVC to change, depending on which VC called it.
So here's the problem- how can I tell which view controller called the popup? It's basically the view that's below the popover. Currently I'm storing it as a variable but that's not ideal. I'm guessing it has something to do with the segue identifiers?
Any and all help much appreciated!
One approach to this is adding a property to your pop up view controller and then define the
prepareForSegue:sender:
method so you set your destination view controller's property to the sender of the segue.

Calling multiple views from Uipopovercontroller list view contents

How can I call individual view controllers when I tap each row from my Pop Over List View in the most effective way? Meaning, I don't have to recode to build the Pop Over List View component in each of the individual view controllers, they can sort of share it like a navigation tool.
What I Have Built
I have built the pop over view controller list on my Main View Controller.
This is the 1st view that gets loaded when appDidFinishLaunching is executed.
So, when we run the app, this is what we get:
Link to screenshot of the Pop Over List View:
http://s14.postimage.org/63k567vtd/image.png
For each row in the above Pop Over list, I have a method where I can put in the codes to:
1. Identify which row was selected
2. Based on the row selected, do any action, like NSLog and stuff
3. All this codes sit in the Main View Controller
The Requirement
I am building a demo app, so all data is dummy data at the moment.
I need to call individual View Controller when each of the row in the Pop Over list is tapped.
Each of the View Controllers, will have their own set of data, own set of UI objects, its own XIB file.
So, if user taps on Applications, it must bring up the Applications XIB file and its functionality, followed by any navigations from here. If Application xib has a button that launches another view, this functionality should be in place too.
However, they all must have the same top Navigation Bar with the Pop Over list button, so user can tap that button and see the Pop Over list anytime in the app.
Please share your view.
Thank you.
I suggest looking in to UISplitViewController. It is a component built by Apple to manage what it looks like you are trying to accomplish. Essentially, you set it up with 2 view controllers; the first (called the "master"), would be your table view. The second (called "detail") would be the view controller that gets switched out.
Once you explore it a little and are comfortable with the terminology, here's the general advice:
Inside the master table view controller's didSelectRowAtIndexPath: method, instantiate the appropriate view controller (based on the indexPath), and set it as the detail view controller, like this:
- (void)tableView:tableView didSelectRowAtIndexPath:indexPath {
UIViewController *newDetailVC = // make and configure a new VC based on indexPath
self.splitViewController.viewControllers = [NSArray arrayWithObjects: self, newDetailVC, nil]];
}
Here are the appropriate links:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UISplitViewController_class/Reference/Reference.html#//apple_ref/occ/cl/UISplitViewController
and further (the later sections of): http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html%23

Resources