viewController.view.superview is nil - ios

I'm trying to implement a page-scroll functionality in my project. I develop for iOS 5, with storyboards (and ARC). This is what I did in my storyboard :
The first viewController (on the left) has a scrollView and a pageControl. Its class is called GlobalDashboardViewController, and inherits from the class DashboardViewController (which inherits from UIViewController). The other 2 controllers are simple UIViewControllers with identifiers (MainDashboard and SecondaryDashboard).
In GlobalDashboardViewController.m, there is only a viewDidLoad, which gets the childViewControllers :
- (void)viewDidLoad
{
[super viewDidLoad];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"MainDashboard"]];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"SecondaryDashboard"]];
}
DashboardViewController.m is a bit more complex. Here are the most important methods :
- (void)viewDidLoad
{
// Calling the viewDidLoad above to populate the childViewControllers array
[super viewDidLoad];
[self.scrollView setPagingEnabled:YES];
[self.scrollView setScrollEnabled:YES];
[self.scrollView setShowsHorizontalScrollIndicator:NO];
[self.scrollView setShowsVerticalScrollIndicator:NO];
[self.scrollView setDelegate:self];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.pageControl.currentPage = 0;
_page = 0;
[self.pageControl setNumberOfPages:[self.childViewControllers count]];
UIViewController *viewController = [self.childViewControllers objectAtIndex:self.pageControl.currentPage];
if (viewController.view.superview != nil) {
[viewController viewWillAppear:animated];
}
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [self.childViewControllers count], scrollView.frame.size.height);
}
There are plenty of other methods, but I don't think they're relevant, because here is my problem: the app launches, and I see the scrollView and the pageControl. The background is dark gray, as I set it in the GlobalDashboard viewController. I can scroll correctly, and the pageControl is updated. But I don't see the other views. When I place a breakpoint at the if in viewWillAppear, and look at viewController, it's named correctly (Dashboard Page 1, which is the name I gave to the controller in the storyboard), but its _view property shows 0x00000000, as you can see here :
So, I never get inside the if, which is where some of the magic of actually showing the viewControllers happens...
My work is based on an example project you can find here : PageViewController. When I run it, it works perfectly. I have no clue why I can't make it work in my own project.
Any ideas ?
Thanks

You never add the view itself ([self.view addSubview:/*Your child controller's view*/]). The project you linked to does it in - (void)loadScrollViewWithPage:(int)page inside PagerViewController.m

Related

add UIViewController in subview

I don't know if this is the right key to search "add UIViewController in subview".
As what you can see in my image ,there are two ViewController, the main and the second controller. Inside the main controller there is a UIView(blue background color). Inside in UIView, I want to add the second ViewController in my UIView. I have this code but It didn't work.
here's my code
#import "ViewController.h"
#import "SampleViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIView *testView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
SampleViewController * sample = [[SampleViewController alloc] initWithNibName:#"SampleViewController" bundle:nil];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self.testView addSubview:sample.view];
}
#end
I want to know if this is possible? I know initWithNibName: works in xib file, I don't the exact term to search in google about this. I'm just trying to experiment something if this is possible in IOS. Hoping you understand what I'm trying to do. Hoping for your advice. Thanks in advance
here's my update
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIView *testView;
#property(strong,nonatomic) SampleViewController * samples;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIStoryboard *storyBoard = self.storyboard;
SampleViewController * sample = [storyBoard instantiateViewControllerWithIdentifier:#"SampleViewController"];
// SampleViewController * sample = [[SampleViewController alloc] //initWithNibName:#"SampleViewController" bundle:nil];
[self displayContentController:sample];
//commented the below line because it is not needed here, use it when you want to remove
//child view from parent.
//[self hideContentController:sample];
}
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.bounds = self.testView.bounds; //2
[self.testView addSubview:content.view];
[content didMoveToParentViewController:self]; // 3
}
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
I always get this error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/ace/Library/Developer/CoreSimulator/Devices/035D6DD6-B6A5-4213-9FCA-ECE06ED837EC/data/Containers/Bundle/Application/EB07DD14-A6FF-4CF5-A369-45D6DBD7C0ED/Addsubviewcontroller.app> (loaded)' with name 'SampleViewController''
I think, its looking for a nib. I didn't implement a nib here.
You should use Child containment concept, here MainViewController is a parent view controller and you want to add child view controller view as a subview on Main View Controller.
Adding and Removing a Child
//call displayContentController to add SampleViewCOntroller view to mainViewcontroller
[self displayContentController:sampleVCObject];
// write this method in MainViewController
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.bounds = testView.bounds; //2
[testView addSubview:content.view];
[content didMoveToParentViewController:self]; // 3
}
Here’s what the code does:
It calls the container’s addChildViewController: method to add the child. Calling the addChildViewController: method also calls the child’s willMoveToParentViewController: method automatically.
It accesses the child’s view property to retrieve the view and adds it to its own view hierarchy. The container sets the child’s size and position before adding the view; containers always choose where the child’s content appears. Although this example does this by explicitly setting the frame, you could also use layout constraints to determine the view’s position.
It explicitly calls the child’s didMoveToParentViewController: method to signal that the operation is complete.
//you can also write this method in MainViewController to remove the child VC you added before.
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
For more details, please refer to apple doc:
https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
Configuring a Container in Interface Builder, for those who don't want to write code.
To create a parent-child container relationship at design time, add a container view object to your storyboard scene, as shown in Figure 5-3. A container view object is a placeholder object that represents the contents of a child view controller. Use that view to size and position the child’s root view in relation to the other views in the container.
When you load a view controller with one or more container views, Interface Builder also loads the child view controllers associated with those views. The children must be instantiated at the same time as the parent so that the appropriate parent-child relationships can be created.
You can do this simply by using StoryBoards
Open storyboards and select the view controller in which your Blue view is present, open Utilities search for ContainerView and drag it into your blue view, this will automatically adds an view controller that acts as child view for your view. You can resize your container view in size inspector.
I've resolved the problem about the uiview on second uiviewcontroller.
Follow the code that I've used:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SecondViewController *sb = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:#"sb"];
sb.view.backgroundColor = [UIColor redColor];
[sb willMoveToParentViewController:self];
[self.view addSubview:sb.view];
[self addChildViewController:sb];
[sb didMoveToParentViewController:self];
I hope to help you.
Thanks a lot
SampleViewController * sample = [[SampleViewController alloc] initWithNibName:#"SampleViewController" bundle:nil];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self addChildViewController:sample];
[self.testView addSubview:sample.view];
You can add a childViewController to UIViewController since iOS5..
it is a great way to maker smaller, more reusable viewControllers, I also really like it.
you're really close, but you just need a couple more lines of code..
///
[self addChildViewController:sample];
[self.testView addSubview:sample.view]; //you already have this..
[sample didMoveToParentViewController:self];
In you viewWillDisappear: or one of the other teardown methods you'll need to clean up like this:
//we'll need another pointer to sample, make it an iVar / property..
[sample willMoveToParentViewController:nil]; // 1
[sample removeFromSuperview]; // 2
[sample removeFromParentViewController]; // 3
You can read the Apple docs on containing child viewControllers here https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
I'm tring to adding UIViewController in subview, and this work.
On UIViewController I've added 2 button, in .h file:
-(IBAction)matchButtonAction:(id)sender;
-(IBAction)closeButtonAction:(id)sender;
And in .m file:
-(IBAction)matchButtonAction:(id)sender
{
NSLog(#"matchButtonAction");
}
-(IBAction)closeButtonAction:(id)sender
{
NSLog(#"closeButtonAction");
}
but I don't see the log.
I need to add same parameter on UIViewController instantiateViewControllerWithIdentifier?
How to resolve the problem?
My UIViewController initialization is:
AlertDialogViewController *alertDialogView = (AlertDialogViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"alertDialogView"];
[alertDialogView willMoveToParentViewController:self];
[viewController.view addSubview:alertDialogView.view];
[viewController addChildViewController:alertDialogView];
[alertDialogView didMoveToParentViewController:viewController];
Since your view controller is in storyboard you should use instantiateViewControllerWithIdentifier to get the VC from storyboard.
SampleViewController * sample = [self.storyboard instantiateViewControllerWithIdentifier:#"IdOfSampleViewController"];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self.testView addSubview:sample.view];
Don't forget the add the identifier for the SampleViewController in storyboard
I've try to use this code:
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
secondViewController.view.frame = CGRectMake(0, 0, self.mySubView.bounds.size.width, self.mySubView.bounds.size.height);
[self addChildViewController:secondViewController];
[self.viewDialogSolution addSubview:secondViewController.view];
but I see only myview not the layout of secondViewController.
Ho to resolve the probleam?
Thanks a lot
let controller:SecondViewController =
self.storyboard!.instantiateViewController(withIdentifier: "secondViewController") as!
SecondViewController
controller.view.frame = self.view.bounds
controller.willMove(toParent: self)
self.view.addSubview(controller.view)
self.addChild(controller)
controller.didMove(toParent: self)

UIScrollView disabled after UINavigationController push and pop

I have looked at the other answers to this question, and none of them have helped.
I have a UIScrollView in my very simple scene, embedded like this:
I use this code to make sure the scroll view will actually scroll, based off of this answer.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self resizeScrollView];
}
- (void) viewDidLayoutSubviews {
[self resizeScrollView];
}
- (void)resizeScrollView
{
_scrollView.scrollEnabled = YES;
[_scrollView setContentSize:_innerView.frame.size];
}
- (IBAction)cameraButtonPressed:(id)sender {
UIViewController *vc = [UIViewController new];
[self.navigationController pushViewController:vc animated:YES];
}
The problem is that scrolling doesn't work after I've pushed and popped the new ViewController (Which originally was an image picker btw).
I don't know why this worked, but I wrapped everything in another view, and it's perfect now.

UIPageViewController as sub view will disable main view events in iOS

I am trying to use UIPageViewController to create walkthrough screens with three separate UIViewControllers. As a summary, I have four View Controllers and a Page View Controller in my storyboard. One view controller act as base view (XYZViewController.h/m) and other three act as sub views that loads inside base view controller. Below shows how the XYZViewController.h displays roughly.
#import <UIKit/UIKit.h>
#import “XYZPageContentViewController.h"
#import "XYZPageTwoContentViewController.h"
#import "XYZPageThreeContentViewController.h"
#interface XYZViewController : UIViewController <UIPageViewControllerDataSource>
#property (strong, nonatomic) UIPageViewController *pageViewController;
#end
Following code snippet shows the viewDidLoad method of XYZViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PageViewController"];
self.pageViewController.dataSource = self;
XYZPageContentViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
self.pageViewController.view.frame = CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height - 60);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
bottomView.layer.zPosition = 1;
startBtnOutlet.layer.zPosition = 1;
}
Actually, loading sub views and walkthrough is working perfectly. What is not working is, the button touch up inside event I have declared in base view.
As you can see with the image, there is "Start again" button at the bottom of the screen. At first that view even didn't display when I set page controller view till bottom of the screen and not using z-index option.
Which means having this line
self.pageViewController.view.frame = CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height - 60);
with commenting following lines.
// bottomView.layer.zPosition = 1;
// startBtnOutlet.layer.zPosition = 1;
What I need is limit the page view controller where the gray view begins and available the sub view till end of the screen. I can limit the page view controller frame as mentioned above, then it is apply to my all walkthrough screens as well. What can I do for that?
I have followed this tutorial. Is there any better way to do this?
Found the solution.
Keep comment below lines of codes.
// bottomView.layer.zPosition = 1;
// startBtnOutlet.layer.zPosition = 1;
Add this line below that code, inside viewDidLoad method
[self.view sendSubviewToBack:_pageViewController.view];

ViewController Containment - Child ViewController not sizing correctly in Landscape

The app is set to only support landscape mode.
The custom UIViewController has the following code:
- (void)viewDidLoad {
[super viewDidLoad];
MBMainViewController *mainViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"MBMainViewController"];
[self addChildViewController:mainViewController];
[self.view addSubview:mainViewController.view];
[mainViewController didMoveToParentViewController:self];
self.mainViewController = mainViewController;
}
When app is launched, the frame for the view of the child viewcontroller (mainViewController) is still set to the dimension of a portrait.
Is there something I'm missing so the right frame size is set on the child viewcontroller's view?
This apparently only happens to UIViewController that are instantiated from storyboard. In this case, it only works if we set the autoresizingMask of the view belonging to the child view controller:
- (void)viewDidLoad {
[super viewDidLoad];
MBMainViewController *mainViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"MBMainViewController"];
// Set the autoresizingMask as a fix
mainViewController.view.autoresizingMask = UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleHeight;
[self addChildViewController:mainViewController];
[self.view addSubview:mainViewController.view];
[mainViewController didMoveToParentViewController:self];
self.mainViewController = mainViewController;
}
My guess is that when you instantiate a view controller from the storyboard, the constraints have already been set or that it doesn't come with the right autoresizingMask values.

Containment and UITableView flashScrollIndicators

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.

Resources