How to control the back button navigation in iPad (UISplitViewController)ios xcode - ios

I have used the following code for deleting my login page from the navigationcontroller(viewcontrollers) so that it will not come into the view again when going back (back button).
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
NSMutableArray *VCs = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
if([[VCs objectAtIndex:[VCs count] - 2] isKindOfClass:[loginViewController class]]&&(VCs.count>=4))
{
[VCs removeObjectAtIndex:[VCs count] - 2];
[VCs removeObjectAtIndex:[VCs count] - 2];
[self.navigationController setViewControllers: VCs];
}
}
This works perfectly for iPhone. But for iPad, since we are using splitViewController, if we code like
NSMutableArray *VCs = [NSMutableArray arrayWithArray:self.splitViewController.viewControllers];
What we will be getting is an array of navigationControllers. Is there a genuine logic by which we can delete a particular viewcontroller from the splitviewcontroller?

Your split view controller, as you said, will return an array of nav controllers (depending on the project setup). Once you have a reference to those, you can manipulate them however you want.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *masterNavVC = (UINavigationController *)splitViewController.viewControllers.firstObject;
UINavigationController *detailNavVC = (UINavigationController *)splitViewController.viewControllers.lastObject;
//Now you have the master and detail navigation controllers, get your VC you need to manipulate
NSMutableArray *masterVCs = masterNavVC.viewControllers;
NSMutableArray *detailVCs = detailNavVC.viewControllers;
//Remove the ones you need to - this example is arbitrary. Put your logic here
if(masterVCs.count > 0 && [masterVCs[0] isKindOfClass:[LoginViewController class]])
{
//Remove or add
}

Related

Pushing and removeFromParentControllers, Affected the structure of navigation controller

enter image description here
Image on above link, cant include it in the post..
As I push from viewControllerA to B, then I push from B to C, then I use the following code to remove the viewControllerB and push C to B and remove viewControllerC:
NSMutableArray *navigationArray = [[NSMutableArray alloc] initWithArray: self.navigationController.viewControllers];
for(UIViewController *tempVC in navigationArray)
{
if([tempVC isKindOfClass:[viewControllerB class]])
{
[tempVC removeFromParentViewController];
}
}
[self performSegueWithIdentifier:#"toViewControllerB" sender:self];
for(UIViewController *tempVC in navigationArray)
{
if([tempVC isKindOfClass:[viewControllerC class]])
{
[tempVC removeFromParentViewController];
}
}
So now ViewControllerA is connected to the last ViewControllerB
After that I still get the back button in the navigation bar, but after I pressed the back button of it, the ViewControllerB popped back to ViewControllerA, but in the ViewControllerA, the navigation bar items and title are gone, I purposely push from C to B again to fix some memory issue, how can I make this work by taking out the two view controllers in the middle but not messing up the navigation controller? Is there any other alternatives to get this done? Thank you
I have another weird approach is to programatically create a navigation bar with the same items and title to cover it, but just seems so wrong...
First when you want to push from B to C and then remove B, you can try this
for(UIViewController *tempVC in navigationArray)
{
if([tempVC isKindOfClass:[viewControllerB class]])
{
[navigationArray removeObject:tempVC];
break;
}
}
[self.navigationController setViewControllers:navigationArray];
[self performSegueWithIdentifier:#"toViewControllerB" sender:self];
But you must ensure the segue is from C to B. Then you will get the Controllers A->C->B. If you want to push to ControllerC and remove Last C. Try to use the same function.
1) When you first push to your C controller from B then first Remove B controller
2) When you push to B controller from C controller then remove C controller.
// Code for removing C Controller from stack
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *viewControllersMutable = [NSMutableArray arrayWithArray:viewControllers];
for (UIViewController *vc in viewControllers) {
if (([viewControllers indexOfObject:vc] != viewControllers.count - 1 ) && [vc isKindOfClass: C.class] ){
NSLog(#"removing contoller of kind C");
[viewControllersMutable removeObject:vc];
}
}
self.navigationController.viewControllers = viewControllersMutable.copy;
// Code for removing B controller
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *viewControllersMutable = [NSMutableArray arrayWithArray:viewControllers];
for (UIViewController *vc in viewControllers) {
if (([viewControllers indexOfObject:vc] != viewControllers.count - 1 ) && [vc isKindOfClass: B.class] ){
NSLog(#"removing contoller of kind B");
[viewControllersMutable removeObject:vc];
}
}
self.navigationController.viewControllers = viewControllersMutable.copy;
Note -> You can do this in a same code Only "OR" condition is checked, means the controller is B or C.

navigationController.viewControllers Works differently in iOS 8.2

In my project, I was using some code to handle the back button as follows.
NSMutableArray *VCs = [NSMutableArray arrayWithArray: self.navigationController.viewControllers];
if ([[VCs objectAtIndex:[VCs count] - 2] isKindOfClass:[LoginViewController class]])
{
[VCs removeObjectAtIndex:[VCs count] - 2];
[VCs removeObjectAtIndex:[VCs count] - 2];
}
[self.navigationController setViewControllers: VCs];
In iOS 7 I am getting the desired result. But for iOS version 8.2, the value in the mutable array VCs is only the current or topViewController in the stack. But the back button will navigate you to all the previous viewcontrollers. But none of them is present there in the navigation stack.Is there any change in the navigation handling in ios8?
I want to delete the login screen viewcontroller from the stack so that on clicking the back button,it will not go back to the login screen. I am facing this issue in iOS 8.2 only (may in iOS 8 and above). What can be the issue?
Edit:
In the prepareForSegue:, I am using the following code:
if([[segue identifier] isEqualToString:#"mediaDetailSegue1"])
{
MovieDetailViewController *movieDetail;
if(isIOS8SystemVersion)
{
movieDetail = ([[segue destinationViewController]viewControllers][0]);
}
else
{
movieDetail = [segue destinationViewController];
}
movieDetail.videoData = [_mediaContentArray objectAtIndex:selectedIndex];
}
so for iOS versions greater than 8,the code
movieDetail = ([[segue destinationViewController]viewControllers][0]);
is called. I think this is causing the issue. Am I doing it wrong?
I got the reason why my navigation Stack is having only one viewController.
In iOS8 and above,if we make a segue from a viewController to a second viewController through the navigationController of the second VC,then the navigationStack of the second VC will contain only the topViewController.
I tried creating a sample project.If the segue is from the VC to second VC directly,then the navigation stack of VC2 will contain VC1 and VC2.If the segue is through the navigation controller of VC2,then the navigation stack of VC2 will contain VC2 only.Strange behaviour of iOS8.
IN both these cases,the app behaves the similar in ios 7.Dont know why it behaves strange in ios8
I'm trying the same with iOS 8.2. self.navigationController.viewControllers returns all view controllers in stack.There is no such issues.I'm not sure Why you are facing such issue.
Try using this Code.It works fine for me.
NSMutableArray *VCs = [NSMutableArray arrayWithArray: self.navigationController.viewControllers];
for(int i = 0; i < VCs.count; i++)
{
UIViewController *vc = VCs[i];
if ( [vc isKindOfClass:[LoginViewController class]])
{
[VCs removeObjectAtIndex:i];
}
[self.navigationController setViewControllers: VCs];

back button doesn't go back

After pushing a ViewController using this code
UIViewController *vc = [[self storyboard] instantiateViewControllerWithIdentifier:#"frontCardViewController"];
[self.navigationController pushViewController:vc animated:YES];
I remove all ViewControllers I don't need anymore using this code
NSMutableArray *navigationArray = [[NSMutableArray alloc] initWithArray:self.navigationController.viewControllers];
NSArray *array = [[NSArray alloc] initWithArray:navigationArray];
for (UIViewController *viewController in array) {
if ([viewController isKindOfClass:[RITCardViewController class]]) {
RSLog(#"Is kind of Class RITCardViewController");
[navigationArray removeObject:viewController];
}
}
self.navigationController.viewControllers = navigationArray;
The navigation array now looks like this:
"RITMainViewController: 0x10d81fc1>",
"RITDetailViewController: 0x10d847880",
"RITTestResultViewController: 0x113d0e090"
But the problem is that if the back button in the navigation bar is pressed now, it goes back to the second screen. But when the back button is pressed again it just stays on this screen. It seems to go trough all the screens I have removed, but doesn't show them.
What am I doing wrong?
Try something like this instead:
NSMutableArray *viewControllers = [#[] mutableCopy];
for (UIViewController *vc in self.nagivationController.viewControllers)
{
if (NO == [vc isKindOfClass:[RITCardViewController class]])
[viewControllers addObject:vc];
}
self.navigationController.viewControllers = viewControllers;
Make sure you don't corrupt the stack by removing the view controller you are currently on from the view controllers array. Assuming your current view controller is not an instance of RITCardViewController you should be fine. Otherwise, you'll have to make up for it in your code.

StoryBoard - UITabBarController + UINavigationController - Jumping from one navigation controller to the other one

I have the following storyboard setup
I need to jump from the BodyMapViewController to MoleDetailsView controller (as shown in the image) when the user hit the save button
I can use the modal view which is very easy but the issue is that I want the user to be able to go back to the MoleHistory and dermalHistory views from the MoleDetailsView
basically I need to do the following steps:
switch the tab
Navigate trough the DermalHistoryView and then MoleHistoryView to get to the MoleDetails view
The idea is that you need to switch tabs and manually modify the view hierarchy so the correct view is showing.
First, grab the navigation controller controlling the other tab. With that, you can then instantiate a view hierarchy with an NSMutableArray like follows:
-(void)pushToMoleDetailViewController:(id)detailItem
{
UINavigationController *navCon = [self.navigationController.tabBarController.viewControllers objectAtIndex: 1];
UIStoryboard *storyboard = self.storyboard;
DermalHistoryViewController *dermalHistory = [storyboard instantiateViewControllerWithIdentifier:#"DermalHistoryViewController"]
//configure dermal history here
NSMutableArray *viewControllers = [[self navigationController].viewControllers mutableCopy];
[viewControllers addObject: dermalHistory];
MoleHistoryViewController *moleHistory = [storyboard instantiateViewControllerWithIdentifier:#"MoleHistoryViewController"]
//configure mole history here
[viewControllers addObject: moleHistory];
MoleDetailsViewController *moleDetails = [storyboard instantiateViewControllerWithIdentifier:#"MoleDetailsViewController"]
//configure mole details here
[viewControllers addObject: moleDetails];
navCon.viewControllers = viewControllers;
self.navigationController.tabBarController.selectedIndex = 1;
}
Take a look at this question:
Push segue without animation

How can we change views in a UISplitViewController other than using the popover and selecting?

I have done a sample app with UISplitViewController studying the example they have provided. I have created three detailviews and have configured them to change by the default means. Either using the left/master view in landscape AND using the popover in the portrait orientation.
Now I am trying to move to another view(previous/next) from the currentView by using left/right swipe in each view. For that, what I did was just created a function in the RootViewController. I copy-pasted the same code as that of the tablerow selection used by the popover from the RootViewController. I am calling this function from my current view's controller and is passing the respective index of the view(to be displayed next) from the current view. Function is being called but nothing is happening.
Plz help me OR is anyother way to do it other than this complex step? I am giving the function that I used to change the view.
- (void) rearrangeViews:(int)viewRow
{
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
if (viewRow == 0) {
DetailViewController *newDetailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (viewRow == 1) {
SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc] initWithNibName:#"SecondDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (viewRow == 2) {
ThirdDetailViewController *newDetailViewController = [[ThirdDetailViewController alloc] initWithNibName:#"ThirdDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
if (rootPopoverButtonItem != nil) {
[detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
[detailViewController release];
}
I have googled and found a nice approach. They use a UINavigationController on the detail view to push new views. You could use this same solution for your project.
http://www.cimgf.com/2010/05/24/fixing-the-uisplitviewcontroller-template/

Resources