I'm using a custom rootViewController, and am using the code below to access it from any UIViewController
#implementation UIViewController(CustomRootVC)
- (CustomRootVC*)customViewController
{
UIViewController *parent = self;
Class customClass = [CustomRootVC class];
while ( nil != (parent = [parent parentViewController]) && ![parent customClass] )
{
}
return (id)parent;
}
#end
If I call self.customViewController on viewDidLoad I get nil. If I call it on willAppear I get the reference I expect.
I'm guessing this is something to do with the order I add the view controllers to my view controller container (i.e. viewDidLoad is called before the view controller has been added to customViewController and so it isn't a parent), but I can't spot anything obvious. I add the view controllers as follows:
- (void)addViewController:(UIViewController*)controller toWrapper:(PLSliderView*)wrapper{
[self addChildViewController:controller];
[self addView:controller.view ToWrapper:wrapper];
[self.viewControllers addObject:controller];
[controller didMoveToParentViewController:self];
}
In particular, the issue seems to be with adding a new view controller and view as follows:
- (void)replaceTopOfStackWithViewController:(UIViewController *)newController animated: (BOOL)animated {
UIViewController *oldController = self.currentController;
[self addChildViewController:newController];
[self transitionFromViewController:oldController
toViewController:newController
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:nil
completion:^(BOOL finished) {
[self.rightViewController didMoveToParentViewController:self];
[self removeViewController:oldController];
[self queryDimensions:#"REPLACE"];
[self.view setUserInteractionEnabled:YES];
self.currentController = newController
}];
}
The view controller hasn't been added to the view controller hierarchy at the time viewDidLoad is called, hence it has no parent view controller, hence your function returns nil as expected.
this piece of code (parent = [parent parentViewController]) sets parent equal to self.parentViewController. If self does not have a parent view controller at the time this is called, it would return nil as expected.
more broadly, I'm not sure what you're trying to accomplish with this code, or why you need to use a category. it seems like that sort of behavior would make more sense in a UIViewController subclass.
Related
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];
I have a method that takes a viewController and an identifier and returns a viewController. It looks like this:
- (UIViewController *)createStepVC:(UIViewController *)viewController identifier:(NSString *)identifier
{
viewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
[_scrollView addSubview:viewController.view];
[self addChildViewController:viewController];
[viewController didMoveToParentViewController:self];
viewController.view.translatesAutoresizingMaskIntoConstraints = NO;
return viewController;
}
In viewDidLoad I call it like this:
_step1VC = (TNSettingsViewController *)[self createStepVC:_step1VC identifier:#"TNSettingsViewController"];
_step1VC which is of type TNSettingsViewController inherits from UIViewController.
When I try and run it - this happens:
The scrollView is an IBOutlet which is connected. All the storyboard ID's are correct. I have no idea as to why this is happening.
Any help would be greatly appreciated!
According to the error message, most likely somewhere in your Storyboard you have a view that points to backgroundImage outlet which is no longer presented in TNSettingsViewController.
I have written a custom view controller container that can replace the existing view controller (VC1) with a new view controller(VC2) i.e. a replace type segue rather than pop/push.
Everything worked fine until testing with iOS 8. It seems a second party I'm using causes a crash if the view controller is replaced before the previous view controller is dealloc
i.e. if [VC2 viewDidLoad] called before [VC1 dealloc].
It is my understanding that I have no control over the dealloc so this kind of behaviour is out of my control. However, I want to make sure that I am not causing this behaviour in the way I'm controlling my child view controllers.
The following is pseudo code for my view controller container:
- (void)replaceStackWithNewController:(UIViewController*)newVC {
for(UIViewController *vc in [self viewControllers]) {
[vc willMoveToParentViewController:nil];
if([vc isViewLoaded]
[[vc view] removeFromSuperview];
}
[vc removeFromParentViewController];
}
//self.viewControllers is my navigation stack
self.viewControllers = nil;
self.childVC = nil;
if(newVC != nil) {
self.childVC = newVC;
}
[self addChildViewController:newVC];
//this adds the view to a pre existing wrapper
[self addView:newVC.view ToWrapper:wrapper];
//add controller to stack
[self.viewControllers addObject:newVC];
[newVC didMoveToParentViewController:self];
}
I currently have a Parent ViewController which contains a child UIViewController (Child). The child UIViewController has a UITableView. On Child.viewDidAppear I invoke the TableView.flashScrollIndicators.
For some reason the scroll indicators are not flashing. I've noticed if I put a dispatch_after call, the second pass does a flash. I thought at first it was a size issue, but I don't think that's it. It seems to be a layout issue (I'm using Storybards, iOS 7, and no AutoLayout). Any ideas?
Here's my code for creating the Child.
- (void)viewDidLoad {
[super viewDidLoad];
// add it to the heirarchy
if ([[self childViewControllers] count] == 0) {
[self setViewControllers:[[NSMutableArray alloc] init]];
ProductSelectionViewController *destination = (ProductSelectionViewController *)[[self storyboard] instantiateViewControllerWithIdentifier:#"ProductSelectionViewController"];
[self addChildViewController:destination];
// present the child
[destination didMoveToParentViewController:self];
[[self containerView] addSubview:[destination view]];
[[self viewControllers] addObject:destination];
[destination setDelegate:self];
}
}
For me, it worked to call
[self performSelector: #selector(flashScrollIndicators) withObject: nil afterDelay: 0];
instead of
[self flashScrollIndicators];
in didMoveToWindow method of the view or in viewDidAppear of its view controller. Hope this helps people with the same issue.
My app allows the user to switch between two different modal view controllers (for two different styles of data entry). The code below used to work (in iOS 4.3 and earlier):
UIViewController * parent = current.parentViewController;
[current dismissModalViewControllerAnimated:NO];
svc.modalPresentationStyle = UIModalPresentationFormSheet;
[parent presentModalViewController:svc animated:NO];
[svc release];
but no longer (in iOS 5) - the "current" view controller dismisses, but "svc" is not presented.
Any idea why it broke (i.e. what did I do wrong)?
Any idea how to do it "right" (so that it works on 5.0 as well as 4.3 and earlier)?
Jeff Hay was totally right in his comment except for one thing. You should do it in the -viewDidAppear: method of the view controller which originally presented the first modal view controller.
Example:
// MyViewController.h
#interface MyViewController : UIViewController {
BOOL _shouldPresentSecondModalViewController;
}
#end
// MyViewController.m
#implementation MyViewController
- (void)viewDidAppear:(BOOL)animated {
if(_shouldPresentSecondModalViewController) {
UINavigationController *myNavCon;
// Code to create second modal navigation controller
[self presentModalViewController:myNavCon animated:YES];
_shouldPresentSecondModalViewController = NO;
}
}
- (void)presentFirstViewController {
UINavigationController *myNavCon;
// Code to create the first navigation controller
_shouldPresentSecondModalViewController = YES;
[self presentModalViewController:myNavCon animated:YES];
}
#end
EDIT:
Now, if you want to pass data between the two modal view controllers, you can use a delegate.
// FirstModalViewControllerDelegate.h
#protocol FirstModalViewControllerDelegate
#optional
- (void)controller:(FirstModalViewControllerDelegate *)vc shouldShowData:(id)anyType;
#end
// MyViewController.h
#interface MyViewController : UIViewController <FirstModalViewControllerDelegate> {
id _dataToDisplay;
}
#end
// MyViewController.m
#implementation MyViewController
- (void)viewDidAppear:(BOOL)animated {
if(_dataToDisplay != nil) {
UINavigationController *myNavCon;
// Code to create second modal navigation controller
[self presentModalViewController:myNavCon animated:YES];
[_dataToDisplay release];
_dataToDisplay = nil;
}
}
- (void)presentFirstViewController {
UINavigationController *myNavCon;
FirstModalViewController *myCon;
// Code to create the first modal view controller
[myCon setDelegate:self];
myNavCon = [[UINavigationController alloc] initWithRootViewController:myCon];
[self presentModalViewController:myNavCon animated:YES];
[myNavCon release];
}
- (void)controller:(FirstModalViewControllerDelegate *)vc shouldShowData:(id)anyType {
/* This method will get called if the first modal view controller wants to display
some data. If the first modal view controller doesn't call this method, the
_dataToDisplay instance variable will stay nil. However, in that case, you'll of
course need to implement other methods to, like a response to a Done button, dismiss
the modal view controller */
[self dismissModalViewController];
_dataToDisplay = [anyType retain];
}
#end