Correct adding and UIViewController to another - ios

Tonight one faced with this:
- (void)loadView {
VC *vc = [[VC alloc] initWithStyle:UITableViewStyleGrouped];
[self addChildViewController:vc];
[vc removeFromParentViewController];
[self setView:vc.view];
}
and got a bomb:
uncaught exception 'UIViewControllerHierarchyInconsistency', reason:
'A view can only be associated with at most one view controller at a time!
Q: How we can directly add vc and all its functionality to current ViewController without AddSubView?

Add your table view controller's view as a subview of the current view. You shouldn't call removeFromParentViewController on vc because that would essentially negate the line before. It's also a good idea to set the frame to match the parent.
- (void)loadView
{
[super loadView]; // this will create a basic view
VC *vc = [[VC alloc] initWithStyle:UITableViewStyleGrouped];
[self addChildViewController:vc];
vc.view.frame = self.view.bounds;
vc.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];
}

Related

how to remove child class from parent when I get sucess message in the childview controller

I am presenting viewcontroller as chid viewcontroller.I Am presenting child viewcontroller in a popupview which is in parent class.plase find the below image to get clear idea.
This the code i used to add present childvc in parent.
[self.view addSubview:yopopup_view];
yopopup_view.hidden=NO;
yoviewcontroller = [storyBoard instantiateViewControllerWithIdentifier:#"yoviewcontroller"];
CGRect contentFrame = yocontantview.frame;
contentFrame.origin.y = yocontantview.frame.origin.y;
contentFrame.size.height = yocontantview.frame.size.height;
yocontantview.frame = contentFrame;
yoviewcontroller.view.frame = yocontantview.bounds;
[yocontantview addSubview:yoviewcontroller.view];
[self addChildViewController:yoviewcontroller];
[yoviewcontroller didMoveToParentViewController:self];
Now i the childvc I have an api class when I get success message from backend I have remove child class from parentvc.
I am using the below code to remove child class from parent class.
[self willMoveToParentViewController:nil];
[self.view removeFromSuperview];
[_delegate closeyopopmethod:#"close"];
[self removeFromParentViewController];
When I use the code I am removing the child class but I have to remove popupview from the parent class superview.How to do that.
Thanks for quick responce.
You haven't set the delegate of yoviewcontroller, so set it to self when you initialized it.
yoviewcontroller = [storyBoard instantiateViewControllerWithIdentifier:#"yoviewcontroller"];
//Set the delegate to self
yoviewcontroller.delegate = self;
//Your other code
UIViewController *vc = [self.childViewControllers lastObject];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

iOS: change view from viewDidAppear

I'm playing around with view life cycles & am having trouble changing a view from the load of a different view.
In my ViewController.h i have:
-(void)viewDidAppear:(BOOL)animated{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
}
However this only causes the view to be between ViewController, and ViewController2 appearing with animation (in a loop).
I used the code in viewDidLoad however neither of the view's loaded (from reading you cannot change view until the viewWillAppear)
Update: When using the code in viewWillAppear, whose view is not in the window hierarchy error is thrown.
How does one change the view from view setup stage?
Update
Using the above code, inside & out of GCD, in viewDidLoad, viewWillAppear & viewDidAppear either results in an infinite loop of animated showing of the ViewController2, or crash on 2nd attempt of segue (result from the loop).
EDITED:
I'm not sure exactly what you're trying to do, but assuming you are wanting the first viewcontroller to appear and then the second viewcontroller to immediately animate on top of the first one, you should be able to accomplish using several options:
First you could just wrap your calls in a dispatch_async call:
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard
instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
});
Or you could use a show modally segue:
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"myModalSegue" sender:self];
});
}
Or you could use a navigation controller and use a standard show segue (formally push). This one doesn't require the dispatch_async:
- (void)viewDidLoad {
[super viewDidLoad];
[self performSegueWithIdentifier:#"myshowsegue" sender:self];
}
I've posted working examples of all three on: github
It is better to exchange views in loadView method.
- (void)loadView {
CGRect rect = [[UIScreen mainScreen] applicationFrame];
MyView *view = [[MyView alloc] initWithFrame:rect];
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
self.view = view;
}

Child View Controller within Parent View Controller

I am making an app where I want to show the child view controller only within the parent view controller i.e. only in 3/4 part of the parent view controller. I have implemented the following code but the child view controller is filling up the whole parent view controller.
My code is:
- (CardsChildViewController *)viewControllerAtIndex:(NSUInteger)index {
CardsChildViewController *childViewController = [[CardsChildViewController alloc] initWithNibName:#"CardsChildViewController" bundle:nil];
childViewController.index = index;
return childViewController;
}
and on viewDidLoad function I am writing:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageController.dataSource = self;
[[self.pageController view] setFrame:[[self view] bounds]];
CardsChildViewController *initialViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = [NSArray arrayWithObject:initialViewController];
[self.pageController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
[self addChildViewController:self.pageController];
[[self view] addSubview:[self.pageController view]];
[self.pageController didMoveToParentViewController:self];
}
I made this by taking help from : http://www.appcoda.com/uipageviewcontroller-tutorial-intro/
Try to change pageController's frame to the following.
CGRect frame = self.view.frame;
CGRect insetFrame = CGRectInset(frame, frame.size.width * 1/8, frame.size.height * 1/8);
Your page view controller is the child, not the view controller you create with your viewControllerAtIndex method.
The easiest way to set up a child view controller is to put a container view in your storyboard, make the child view controller a separate scene, and control-drag an embed segue from the container view to the view controller that you want to be the child.
When you do that the compiler does all the work to set up the connections to manage the child correctly. Your parent view controller's prepareForSegue method will fire when the view is first loaded and the child is installed. At that point you can hook up any outlets, delegate connections, or whatever else you might need.
Failing that, you can adjust the frame of your page view controller's view before adding it as a subview, as #ErAdhish suggests. But you will have a bunch of setup to do in order to forward housekeeping messages from the parent to the child.

setView with ChildViewController

I have ViewController with child, it's works great, but when I change root view to another, and then return back the root view:
-(void)showSearchResultView
{
self.searchView.frame = self.view.frame;
__rootView = self.view;
[self setView:self.searchView];
}
-(void)hideSearchResultView
{
if(__rootView) [self setView:__rootView];
__rootView = nil;
}
I'm getting the exception:
Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency',
reason: 'child view controller:<SlideViewController> should have parent view controller:
<UINavigationController> but actual parent is:<MainViewController>'
What is the proper way to change root view with child view controllers?
For changing root view you have to remove rootviewcontroller from navigation stack.
Like :
NSMutablerray *controllers = [self.navigationController viewcontrollers];
[controllers removeObjectAtIndex:0];
it will remove the rootviewController and name way you can add new view Controllers.
[controllers addObjectAtIndex:0];
Note:- This code syntax might be incorrect .this is just a approach.
Update:-
NSMutableArray *viewControllers = [[NSMutableArray alloc]initWithArray:self.navigationController.viewControllers];
RootViewController *root = [[RootViewController alloc]initWithNibName:#"RootViewController" bundle:nil];
[viewControllers insertObject:root atIndex:0];
self.navigationController.viewControllers = viewControllers;
This way you can change your root view.
I found the solution. Just remove the children root views and add it again.
-(void)showSearchResultView
{
self.searchView.frame = self.view.frame;
__rootView = self.view;
[self setView:self.searchView];
for(UIViewController* vc in self.childViewControllers){
[vc.view removeFromSuperview];
}
}
-(void)hideSearchResultView
{
if(__rootView) [self setView:__rootView];
__rootView = nil;
for(UIViewController* vc in self.childViewControllers){
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
}
}

Issue with definesPresentationContext / UIModalPresentationCurrentContext - Current context view controller gets lost

This only accours if you are presenting in a view controller that is managed by a navigation controller.
The reproduction steps are:
1 - Present a view controller using UIModalPresentationCurrentContext
self.definesPresentationContext = YES;
ViewController* viewController = [[ViewController alloc] init];
viewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentOnViewController presentViewController:viewController animated:YES completion:nil];
2 - Present a view controller over the top using the default full screen presentation style
ViewController* viewController = [[ViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
3 - Dismiss the top presented view controller (the full screen one)
[self dismissViewControllerAnimated:YES completion:nil];
Now the problem is the 2nd view controller (presented using UIModalPresentationCurrentContext) disappears. Also it is impossible to present another view controller using UIModalPresentationCurrentContext, because the system thinks its still there.
I believe the issue is a bug in the framework. As mentioned it only occurs when the presenting in a view controller managed by a navigation controller. There is a nasty work around which uses the containment API. It creates a dummy view controller which views are presented from. The steps are:
1 - When presenting a view in context who's parent is a navigation controller, use a dummy view controller:
- (void)presentInContext
{
UIViewController* presentOnViewController = self;
if ([self.parentViewController isKindOfClass:[UINavigationController class]])
{
// Work around - Create an invisible view controller
presentOnViewController = [[DummyViewController alloc] init];
presentOnViewController.view.frame = self.view.frame;
// Containment API
[self addChildViewController:presentOnViewController];
[self.view addSubview:presentOnViewController.view];
[presentOnViewController didMoveToParentViewController:self];
presentOnViewController.definesPresentationContext = YES;
}
ViewController* viewController = [[ViewController alloc] init];
viewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentOnViewController presentViewController:viewController animated:YES completion:nil];
}
2 - When dismissing the view controller tidy up
- (void)dismissSelf
{
__weak UIViewController* presentingViewController = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
// Remove the dummy view controller
if ([presentingViewController isKindOfClass:[DummyViewController class]])
{
[presentingViewController willMoveToParentViewController:nil];
[presentingViewController.view removeFromSuperview];
[presentingViewController removeFromParentViewController];
}
}];
}
Thats it... The fix is dirty, but does the trick with no visual flicker.

Resources