Complex storyboard navigation - ios

I'm very new to iOS but have been put on a complex app. All the tutorials I have seen on storyboards, segues, views, etc. are very simple.
I have been able to use a segue to show a view and go back, but management doesn't care about segues. After moving through a complex app the user is supposed to be able to just jump way over to another part of the app, as if the user had gone back twice then selected another view, and then selected another view.
I'm just lost as to how to make this happen. Add a new direct segue in the storyboard editor? Or something to do with a custom segue created programatically? I need some hints on direction, like what methods to look at, what to google or a advanced tutorial and such. Thanks in advance.

Usually, the Navigation Controller allows single 'pop's of view controllers in the stack. This works great for master-detail apps and linear workflows.
When one view controller is connected to another in a web-like fashion, things get difficult to manage.
If you want to rely on the automatted management of a view controller stack but go back more than one item at once, have a look at unwind segues: What are Unwind segues for and how do you use them? -- the answer is illustrated really well.
If you can navigate in circles, it gets more intricate. Essentially, your navigation controller would put new objects of already intantiated classes onto the stack to maintain its breadcrumb trail all the way back to the root view controller.
In some cases, this is not desirable. You could use a UINavigationControllerDelegate which removes items from the stack when certain conditions are met.
Let's say you have 4 view controllers, A--D. The possible connections are: A - B - C - {B,D} - A. From D, when you're finished, you want to unwind to A. From C, you may want to add an additional item at B, but you don't want to keep track of all the B-C-B-C-B-C-... connections. In these cases, altering the navigation controller history is useful and won't break the expected behavior of the "back" button.

Related

How can I elegantly navigate from one embedded view to another (with layout in IB)?

In this app the user can do either Activity A or B. When doing A, the viewer sees embedded View A; but also during A the viewer can choose to see embedded View B. (The same goes for Activity B, only with converse views.)
My setup in IB is diagrammed below. Not knowing any better way, I created twice as many activity scenes as I would have liked: For the "Do Activity A" branch, I have two side-by-side copies of the Activity A scene. The first one has an embed segue to View A; and the second, an embed segue to View B. (The "B" setup is the converse.)
To avoid more duplication, I did make both activity branches share Views A and B. And although the activity scenes were doubled, the classes that they link to (ActivityAViewController and ActivityBViewController) were not. I haven't yet noticed any complications from that. . . .
In contrast to other workarounds I've seen, I chose the above "push–pop" layout because Views A and B are expensive. I don't want to discard the primary view just to load the secondary, and I don't want to load both unnecessarily. Also, I want to do this in IB because the real app is more complicated, and seeing all of my layout there helps me understand and develop it. With that said, my approach still seems klutzy.
My questions are
Is there a better way to set this up in IB?
What happens with the activity scenes' shared view controllers? Is a separate class instance created for each, or do the two scenes end up sharing the same instance?
Similarly, what happens with the shared views?
Apple's explanations seem clear enough, though they assume more knowledge of Cocoa Touch and related jargon than I currently have. Any clarifications and insights will be appreciated.
Is there a better way to set this up in IB?
There are other ways to set it up. They all have tradeoffs. Your method has a certain look, and if you want to hook it up differently, it will look a little different. Your method also has the advantage that all of the navigation is handled by the Storyboard; no extra code is needed.
Alternatives include imbedding views A and B in their own little navigation controller. Then switching to view the other would involve clicking on that navigationController. This avoids the duplication of the outer Activity A and B controllers, but it would change the look by adding a navigationBar to the embedded views.
You could also do that and hide the navigation bar and pass a message from the outer Activity A or B controller to tell it when to push the other viewController. This has the disadvantage of some additional nontrivial coding; the Storyboard no longer manages the navigation for you.
You could also run this in a UITabBarController. That has the disadvantage of creating both Activity A and Activity B at the same time if you only need one, but you can freely switch between them without any recreation of any of the views.
What happens with the activity scenes' shared view controllers? Is a
separate class instance created for each, or do the two scenes end up
sharing the same instance?
Every segue (including embedded segues) creates a new viewController instance. No instances are shared.
Similarly, what happens with the shared views?
A new instance of A and B will be created each time.

How to share controller amongst different iOS views

I am coming from a C# wpf background where you can have one ViewModel handling multiple Views. This is a great way to share data amongst unrelated views. However I can't figure out how to do the same thing in iOS, as you seem to need a Controller for each View.
What I am trying to achieve is to have a sign up sequence where the user populates 5 screens of data one by one. I was going to use a PageViewController for this and each click on Next would transfer them to the next page in the sequence. All the while, adding all their input data to a parent model object which stayed around for all five screens, at the end you can submit the whole lot to the database to sign up.
The only way I can see so far to do this is to create five separate ViewControllers, one for each screen of the sign up, and create the navigation logic to display them as you click through. However this a) seems overkill and b) means each subsequent screen and viewcontroller doesn't know about the information the user entered in the previous steps.
What is the correct way to do this in iOS?
You can do it in many ways. If you like to use UIPageViewController, you can actually have one view controller for all steps of the sign up process.
A main view controller would implement protocol UIPageViewControllerDataSource. It has two required methods, which return an instance of a content view controller. These instances can be of any UIViewController subclass, so you could have five separate view controller classes or you could have five instances of the same class.
Xcode has a project template "Page-Based Application". It might be a good sample code for you. There is one class DataViewController and it is instantiated for each page. If your case is really simple then this might be the best solution.
If you use multiple view controllers, you can pass data between them by overriding the method prepareForSegue(segue:sender:). The UIStoryboardSegue object has access to the destination view controller, you can cast it and set up the properties. (I am assuming you are using storyboards and segues.)
Another approach would be not to use UIPageViewController and implement the whole process within one view controller. There could be one view with five container subviews. Initially the first one would be shown, then the second one, and so on. This requires manual implementation of navigation between those steps, but gives a lot of flexibility. It's also more aligned with MVVM, because there is one-to-one mapping between a ViewModel and ViewController.
In general, iOS apps have lots of view controllers. It doesn't seem an overkill for me to use five in your case. It might be more code, but it's less complexity.

Perform a series of storyboard segues

I have a storyboard with over 20 scenes. I want to be able to deep link to one of these scenes. In order to do so, I'd like to perform the necessary segues from my initial view controller.
So say I have view controllers A, B, and C with segues laid out as follows.
->A --segue1--> B --segue2--> C
What's the easiest way to get from A to C without adding special code to B? I need the unwind segues from C to B to remain intact. The only solution I've come up with to add special logic in B that performs segue2 after appearing if a flag is set. This is not ideal as I have some use-cases where this chain is much deeper. I'd rather have code in A that does something like [A performSegues:[#"segue1", #"segue2"]].
Is there a better way to do this?
Thanks!
You can use setViewControllers:animated: to build the whole stack of view controllers that you want all at once. If you start with A, you can make a mutable copy of the navigation controller's viewControllers array, add as many other view controllers to it as you need, then pass that array to setViewControllers:animated:. If you set animated to YES, you will see a single push from A to what ever the last controller in the array is. You will still be able to use an unwind to go back to any of those controllers.
I don't think there's any good way to do this with segues, as you would see all the transitions from one controller to the next (unless that's what you want to see).

Multiple Segues to one ViewController with NavigationController?

i have one question about using multiple segues to one ViewController. Ill try to create an article management, so you can add/edit/delete articles.
When you add a new article you can choose between a maincategory and a subcategory, choose the article and then edit some inital values.
but if ill try to edit one of my selected articles, i would like to jump to the "latest" ViewController in navigation stack.
I thought i could easily create another segue to my last viewController, but ill always get an error when i try to load this segue (i guess this could be a problem with the existing NavigationController).
I could provide some code, but i dont know if this is a possible solution to solve such things - or is there a better way?
Thanks in advance.
You can, but the new segue should take you to a navigation controller that just contains the last view controller (as the root). In this way you are duplicating the normal situation but with only 1 view controller.
If you wanted to allow the last view controller to have a 'back' button which took you to some 'earlier' screens (if that makes any kind of sense in your app) then you would need to write some code. It's more likely that other screens should be accessed via bar button items or similar (which would also likely be done in code).

View Container vs Multiple ViewControllers vs Hidden Views Single ViewController

I have a View Controller and need to segue into another View Controller (which is customized based on what scenario I want to show). Trying to decide what is the best approach here in regards to simplicity vs efficiency
Three options I can think of:
(a) Have my View Controller segue into a View Controller that holds a View Container linked to multiple View Controllers
(b) Have my View Controller segue into a View Controller with multiple views that can be hidden and rearranged
(c) Have my View Controller segue into different View Controllers depending upon the criteria
I'm still uncertain how much each View Controller should differ from each other, but given that one View Controller might segue into another View Controller that's irrelevant for the other two scenarios, what are your guys' thoughts on the three approaches in terms of code complexity, ease of use, general efficiency in terms of speed/memory management. It's possible that the View Controllers that are being segued into might differ by just a little, but also by a lot!
I think all depends on difference between viewControllers for each scenario. BUT what I can certainly say is do not use varriant (B), because even if difference seems tiny now, as only it begins growing, your code that compose views will becomes more complicated and unreadable, at least in my case it usually happens. So, if you must show different viewControllers with same or pretty similar use (e.g. save for, show list, select item from list. go next, go previouse), try to use one viewController and load different views that are already composed. And if usage of those controllers different - use multiple controllers.

Resources