Circular application flow - Need Idea - ios

I have an screen (My Profile) which can be accessed from two paths:
Login -> Content -> Profile
Login -> Register -> Profile.
In both paths, view's are shown with:
[self.navigationController pushViewController...];
But my problem is, after the user registers and completes his profile, it should go "Back" to the Content view. (Obviously it won't work with navigation controller stack, since Content isn't in the navigation controller).
My question is, what suggestions do you have?
PS: I know this isn't an actual question, but I've been thinking about this for a few hours now and I didn't come up with anything. Maybe some of you have had to deal with similar cases.
Edit: Basically the question can be generalised to:
How do you deal with a circular application flow?
Edit: I've solved this by pushing from Register to Content and then Profile in viewWillAppeare without animation (so what I need is in the stack), but I'm still interested in dealing with circular application flows.

My suggestion would by to change [UINavigationController viewControllers].
So after you end your registration you can do something like
ContentVC *content = [[ContentVC alloc] init];
[self.navigationController setViewControllers:[NSArray arrayWithObject:content]];
[self.navigationController popToRootViewControllerAnimated:YES];

Push Contentview controller after profile complated in second case , while in first case you have already pushing it.

1)Make your Login viewController the rootController of the a UINavigationController.
2)From Login you can Push Content ViewController
3)From Content VC you can push to Profile VC.
Now if you want to get back to Content from profile do this:
[self.navigationController popViewControllerAnimated:YES];
And if you want o get back from Profile directly to Login do this:
[self.navigationController popToRootViewControllerAnimated:YES];
If you do not want the navigation bar you can hide the bar.
Update
Take a different approach, other than the navigation controller stack:
1) Make a controller class with a 2 functions:
-(void)loadViewControllerWithIndex:(int)index;
and
-(void)unLoadCurentViewController;
2) You can call these functions and load and unload the view controllers from a this controller class.
3) So you initially load this class and import file in this class of other view controllers. You can take a UIViewController object topViewController, so that you can you can keep a track on which controller is currently displayed and it will help when you want to unload a controller.
4) In load controller with Index function you can add the controller view and in unload you may remove them.

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.

Navigation to previous scene on iOS 8

I am working on an iOS 8 application that requires authentication to a backend. I would like to make the app in such a way that, if the app receives an HTTP 403 error, the user is presented with a login screen. After the login screen view controller successfully authenticates the user, the app should navigate back to the previous screen (whatever screen it was).
In Xcode 6, I can see that the preferred way to navigate between scenes is via segues. As such, I am using segues to navigate back from the login screen, with this code:
[self performSegueWithIdentifier:#"UnwindToNewsfeed" sender:self];
The problem that this presents is, I would have to establish segues to all scenes within the app, as any of them might trigger an authentication request. Therefore, I would like to ask for a recommended approach to implement this navigation requirement.
I'm new to iOS8 and to iPhone programming in general, so it could be that I don't have iOS 8's navigation concepts entirely clear and I'm using a wrong approach.
Unwind segues are different to forward segues and this makes it quite simple to support the functionality you are after.
Prior to creating an unwind segue you need to add a method to the view controller that you want to unwind to. For example -
- (IBAction)unwindFromLogin:(UIStoryboardSegue*)sender {
}
You can then create an unwind segue by ctrl-dragging between an object in your scene (or the UIViewController object for your scene if you want to trigger the unwind with performSegueWithIdentifier) and the exit icon at the bottom of the screen. Interface Builder will then display the list of methods it found that match the signature above (so it will display unwindFromLogin:). You can give this segue an identifier so that you can invoke it with performSegueWithIdentifier as you would normally do. So far so good.
Now, for the clever bit. At runtime when the unwind segue is invoked, iOS looks through the current view controller stack to find the first view controller that implements the nominated method - so if you implement the same unwindFromLogin: method in each of your view controllers, your login view will unwind to the view controller it came from and you only need a single unwind segue in your login view controller scene.
Apple has a good Tech Note that describes the unwind process in more detail and how you can customise it by implementing additional methods in your UIViewController subclass, but the default implementation should suit your needs.
If you don't want to create a segue from each source view controller to the login view controller you can present it directly using something like -
LoginViewController *loginVC=(LoginViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"loginVC"];
[self presentViewController:loginVC animated:YES completion:nil];
You can still use the unwind segue to get back
I don't think using segues is always the best approach. In a case like this, it might be better to use -popToViewController:animated:.
That said, using an unwind can still work here. I would recommend creating a custom view controller that subclasses UIViewController. This view controller implements your -unwindXXX: method.
#interface MYBaseViewController : UIViewController
- (IBAction)unwindXXX:(UIStoryboardSegue *)sender;
…
#end
Have all the view controllers which can be unwound to from the login view controller inherit this custom view controller.
#interface MYNewsFeedViewController : MYBaseViewController
…
#end
I consider the two answers below to be valid, and I voted them both up.
However, after testing, I found this approach to be simpler and less cumbersome to my scenario.
On any screen that can trigger a login prompt, I force the login screen to be presented by calling the following method:
LoginViewController *loginView = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginView"];
[self presentViewController:loginView animated:YES completion:nil];
Then, in order to enable the back navigation functionality required after the user successfully authenticates in the login screen, the login screen calls this method, which returns to the previews scene:
[self dismissViewControllerAnimated:YES completion:nil];
As I am new to iOS dev, I am not sure if this is following recommended practices, so I'd like people to comment on whether this is a recommended approach or not.

iOS Navigation Controller/Storyboard Segues Major Upside?

Alright I'm really failing to see what the big win in having Navigation Controllers wrap my views and trying to drag segues on my Storyboards are. Sure you get the benefit of iOS automatically adding a back button as you push/pop views off the stack, but for anything past a simple app, I don't even care for that!
My goal is simply to have 1 view actually represent a given page. Then just programatically move to another view using:
ViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:#"ViewController"];
[self presentViewController:modalYearPickerViewController animated:NO completion:nil];
or
ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:vc animated:YES];
I realize that in order to push with the second example I'd need the view to be wrapped in a Navigation View Controller, however using one of these methods prevents my from ever having to create "segues" which I find hard to manage. Half the time when I setup a segue iOS throws an error saying it cannot perform or the segue doesn't exist.
A lot of the time I'm either hiding back buttons or on the fly changing where "back/return" may drive the user based on previous actions or screens.
Anything massive I'm missing here? I am fairly new to iOS but I come from the web world where I'm used to being able to navigate around screens with ease.
Anyone have any thoughts?
EDIT: Here is a dead simple example solution. When I get to the "details" page I want to have a back button to the home page instead of the modal.
http://andrewherrick.com/spike/nav_ios.zip
From your diagram, I'd expect:
At the root, you have a navigation controller which contains the Artists. Artists has a modal segue to New Artist (well, to a nav controller containing it) and a push segue to Artist Songs.
New Artist is the root of a navigation controller and has a push segue to Artist Songs. New Artist has a Cancel and a Done button in the navigation bar.
Artist Songs should be configurable (it could determine this itself), such that it has a back button (always based on this model, and automatically handled) and a Done button when it is pushed from New Artist (which completes the save and dismisses the modal, thus taking the user back to Artists).
All of the above is a achievable either with segues or direct instantiation and transition from code, which you use is a matter of personal preference.

iOS Showing views conditionally

I have a view in which a user selects an action to take and on that next screen there is a save and a back button. For both of the buttons the last line is dismissViewControllerAnimated:.
I need a way to make the 1st screen show only if the back button is used. save should send back to the main screen/rootViewController I am fairly new to iOS but not programming in general and just need a nudge in the right direction.
Could I set a bool flag to show or not? Maybe I can set the Tag on the view and then check that in the other screens on save/back? I assume I can check the parent view.
Sorry if this is a dup but I cant find anything specifically for this.
EDIT: I am not using a nav controller and am showing the views modally.
The answer will vary depending on how your UIViewControllers are structured and setup. If you're using a uinavigationcontroller then you can POP to the root view controller using:
[self.navigationController popViewControllerAnimated:YES];
If you're presenting your UIViewControllers modally, you can try to dismiss the presenting View Controllers of your modal view controller using the presentingViewController property:
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
You may also want to take a look at Unwind Segues if you're using a Storyboard:
What are Unwind segues for and how do you use them?
Finally, as far as determining whether the back button is pressed or another button - that depends on how the app is setup. You'll need to use your own logic (probably if / then statements or case / switch) to determine which button was pressed. You also may want to check out the sender argument in IBActions.
John, to have a UINavigationViewController return to it's root viewcontroller, you use:
[nameOfNavController popToRootViewControllerAnimated:YES];
The other guys are correct that the information you've provided is definitely not enough to determine exactly what you need to do.
You can use the presentingViewController property of a modal view controller to access it's presenting controller.
It turns out that I was using the terminology wrong. I am presenting all views modally and that is the issue, there is no navigation controller. I ended up using NSNotification to build a listener and had the main view controller listen and then dismiss the view and hence show itself. Worked a treat.
here is the link to the code I ended up with.
http://iphonedevsdk.com/discussion/114737/view-heirarchy-issues-possibly-from-the-camera
Hopefully this helps someone else.

Storyboards create modal view accessible from anywhere

I need to create a modal "flow" within my app. It is made of two "scenes", these are both UITableViewController subclasses.
The user will be able to push and pop between these two table views.
At any point they will be able to press "Done" (in a nav bar) and dismiss the entire modal view to go back to where they were.
This whole modal flow needs to be accessible from several places in the app. I don't really want to create multiple modal segues to this.
My question is, creating this in a storyboard, would you create a whole new storyboard for this flow (I don't like this).
Would you just create multiple modal segues?
Should I create this flow in the same storyboard file but as a separate entity accessible by the identifier?
Or something else?
Sounds like it would be easier to use a single storyboard, but not create multiple segues everywhere. You can programmatically present the view controller pretty easily:
MyViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
// set any properties on vc here, if necessary to pass it any data
[self.window.rootViewController presentModalViewController:vc animated:YES];
You could place all this code in a helper method to reuse this code more easily, maybe a class method like this:
#interface MyViewController ...
+ (void)presentNewViewControllerModally;
...
#end
Tapping the done button:
[self.window.rootViewController dismissModalViewControllerAnimated:YES];
Note that if there's a good chance you'll never see this modal view controller, you could place that view controller in a separate xib file instead of in the storyboard, and I think that could make things more efficient (storyboard remains more lightweight). In this case, just replace the instantiteViewControllerWithIdentifier message above with:
[[MyViewController alloc] initWithNibName:#"SomeNib" bundle:nil];
...and the rest of the code is the same. I've used this technique for a "login" view controller that would only occasionally need to be presented.

Resources