Presenting a UIViewController from inside another UIViewController? - ios

I'm pretty new to iOS, and am attempting to present a view controller from within another view controller as described here:
Stack overflow answer (see third answer)
and also here on Apple's site
I start with the Hello World Example code. I open up MyViewController.m and modify the updateString() method, adding this code to the end:
{
// Get the application's "window"
UIWindow *window = [UIApplication sharedApplication].keyWindow;
// Get the window's rootViewController (NOTE: Only works on iOS 4.0 or later!)
UIViewController *rootViewController = window.rootViewController;
// Create our new controller
UIViewController *enterNameController = [[UIViewController alloc] initWithNibName:#"HighScore" bundle:[NSBundle mainBundle]];
if (enterNameController != NULL)
{
printf("\nLoaded UIView controller. Installing as actionSheetController...\n\n");
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:enterNameController];
// Present out Enter Name for High Score view as a modal view
// [rootViewController presentViewController:navigationController animated:YES]; // iOS 2.0 and newer
[self presentViewController:navigationController animated:YES completion: nil]; // iOS 5.0 and newer
}
}
I have also created a NIB file called "HighScore.xib" that I put with the other NIB files that came with the HelloWorld, and I also added HighScore.xib to the XCode project, and dragged it into the "Copy Bundle Resources" section.
As-is, I get an error when running and entering text into the edit field:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle (loaded)' with name 'HighScore''
However if I change the final statement to use "rootViewController" instead of "self" then nothing happens. No exception, but no new view is presented either.
Questions:
1) Why won't my NIB load? I'm obviously doing something wrong here.
2) Why does using "rootViewController" instead of "self" produce different results? Shouldn't the rootViewController find the same class as "self"?
Note that when using "rootViewController" I get a warning in XCode: "MyViewController' may not respond to '-presentViewController:animated:completion"

I solved this problem by:
a) Using the tutorial here:
http://timneill.net/2010/09/modal-view-controller-example-part-1/
b) Right-clicking and doing "Get Info" on the .xib file in the XCode project, and modifying its Type to be "file.xib" instead of "sourcecode.xib". Without this second change, it would not load! Bizarre. But this was ultimately the problem!!

Related

Move to next view controller, i am using storyboard

Here is my code
RadarViewController *wc = [[RadarViewController alloc]
initWithNibName:#"RadarViewController"
bundle:nil];
[self.navigationController pushViewController:wc animated:YES];
Here is the error comes after crashing the app.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2015-10-14 12:25:02.596 Quick man help[890:60170] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/brainpulse/Library/Developer/CoreSimulator/Devices/0FD1A490-11AF-468D-96D3-71F37DDD8552/data/Containers/Bundle/Application/35FDBB50-E294-458B-B367-A57E3FC0B594/Quick man help.app> (loaded)' with name 'RadarViewController''
Your Xcode can not find a xib with name "RadarViewController" because you are using storyboard ....
You need to create instance of RadarViewController from storyboard like
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
radarVC = [mystoryboard instantiateViewControllerWithIdentifier:#"radarVCID"];
You need to set radarVCID as storyboardID of RadarViewController in your storyboard
It seems that not all connections as parts of the archive has been already loaded from the storyboard at the moment you call initWithNibName as same as instantiateViewControllerWithIdentifier.
I suggest you to instatiate your view controller in viewDidLoad.
If it won't help, try to look if your storyboard is correct. To achieve this open it as a source code and look at opening/closing tags
After all of that, delete you view controller and re-add.Don't forget to create a copy of your storyboard before performing all of this.
Do something like below:
Select your RadarViewController in storyboard
In Identity Inspector, give RadarViewController identifier in Storyboard ID. for example "capture" as you can see in screenshot
Now write something like below:
RadarViewController *obj = [self.storyboard instantiateViewControllerWithIdentifier:#"youridentifier"];//youridentifier =capture as per screenshot. You can give whatever identifier to `RadarViewController`
[self.navigationController pushViewController:obj animated:YES];

push view controller by search button

i have Storyboard with UINavigationController i have created the first screen with searchbar
i have added second viewcontrol via IB to storyboard
how do i push the second viewcontroller to navigationcontroller ?
i have tried
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
ViewController *screen2 = [[ViewController alloc] initWithNibName:#"ViewController2" bundle:nil];
[self.navigationController pushViewController:screen2 animated:YES];
}
i have set Custom Class of second view controller to ViewController2
but when i run the app and click the search button in keyboard i get the following error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle (loaded)' with name 'ViewController2''
The error you are getting is because Xcode cannot find the xib named ViewController2.
You may just call self.performSegueWithIdentifier(#"identifierToViewController")
But first make sure that your searchViewController is a child of an UINavigationController
Then make sure that the segue has a proper identifier:
First of all make sure that your second view controller class name is : ViewController2
After that in storyboard give your View Controller's class name and Storyboard Id as #"ViewController2", Please refer screen shot.
Actually you use wrong method to create instance of UIViewController as it is used when you use xib file.
Change your code like this :
ViewController2 *screen2 = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[self.navigationController pushViewController:screen2 animated:YES];

Present ViewController on UISplitViewNavigator's MasterViewController

I've created a new XCode project using the SplitViewNavigator template. One of the MasterViewController's navigationItems should present a configuration ViewController (fullScreen on iPhone, popup on iPad).
This config controller has been created in a separate storyboard (Filter.storyboard).
In this storyboard I dragged a ViewController on the stage and embedded it in a Navigation Controller (Editor -> Embed In -> Navigation Controller) because the config itself consists of different screens the user can go through.
The NavigationController has been given a StoryBoard ID "FilterNavController".
I've done this several times in other applications, so this does work. Unfortunately, I can't get it working with the SplitViewNavigator template.
Here is how I try to open the filter controller once the button has been tapped, nothing special about it;
UIStoryboard *filterBoard = [UIStoryboard storyboardWithName:#"Filter" bundle:nil];
UINavigationController *filterNavController = [filterBoard instantiateViewControllerWithIdentifier:#"FilterNavController"];
UIViewController *vc = [filterNavController.viewControllers objectAtIndex:0];
[self.navigationController presentViewController:vc animated:YES completion:nil];
self is the MasterViewController.
From my uneducated point of view, I don't see any reason why this wouldn't work. As I said, it does in other (non SplitViewNavigator template) applications.
The error message I'm getting is the following:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <UINavigationController: 0x7f9bab61a700>.'
No idea what the heck is going on here but it already cost me half a day.
Interestingly, when I just create a UIViewController on the Filter.storyboard and set its StoryBoardID, the ViewController will get presented. However, I need it to be embedded in a UINavigationController.
Any help would be highly appreciated!
For the sakes of completeness, the following method works nicely for instantiating ViewControllers from a Storyboard.
Instead of creating a UINavigationController on the Storyboard, just create the ViewController(s) and embed them in a UINavigationController on code.
UIStoryboard *myBoard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
MyViewController *menuController = [myBoard instantiateViewControllerWithIdentifier:#"MyViewController"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:myController];
[self presentViewController:navController animated:YES completion:nil];

Is it possible to instantiate a View Controller from a Storyboard for Kiwi Testing

I'm in for testing some code within a ViewController (that certain controls are active depending on the state of certain UISwitches etc) and decided to go for Kiwi for it, since we are using it for some other low-level logic testing.
My expectation is to run tests like this:
__block AViewController *aVC;
it(#"(tokenTextField) should be hidden if the token switch is set to off", ^{
lvC.useTokenSwitch.on = false;
[[theValue(aVC.tokenTextField.hidden) should] equal:theValue(YES)];
});
My problem is with the initialisation of the AViewController. If I did:
aVC = [[AViewController alloc] initWithNibName:#"aViewController" bundle:nil];
I would be getting a "AViewController" without any controls initialised, so I'd have to init each of them manually.
So I have tried obtaining the AViewController doing this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
aVC = [storyboard instantiateViewControllerWithIdentifier:#"AViewController"];
Yet this results in an error message:
NSInvalidArgumentException "Could not find a storyboard named 'MainStoryboard' in bundle NSBundle </Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/Developer/usr/bin> (loaded)" raised
I have included the MainStoryboard in my testing target, and also included it in "Build Phases" -> "Copy Bundle Resources" and still nothing.
So I am wondering if it is even possible to instantiate a ViewController from a Storyboard in a Kiwi Testing Target? (As I haven't seen any examples of it anywhere).
Is my approach wrong and I should be mocking the ViewController?
Am I missing something to be included in the test target?
The problem is that you’re passing nil for your bundle. You can see in the error message the bundle it’s using. In a unit test, you probably want to do something like this:
Class viewControllerClass = [myViewController class];
NSString *className = NSStringFromClass(viewControllerClass);
NSBundle *classBundle = [NSBundle bundleForClass:viewControllerClass];
MyViewController *viewController =
[[MyViewController alloc] initWithNibName:className
bundle:classBundle];
By looking for the bundle that contains your view controller’s class, you’ll also get the nib file for it.
For storyboards, the code is similar:
Class viewControllerClass = [myViewController class];
NSString *className = NSStringFromClass(viewControllerClass);
NSBundle *classBundle = [NSBundle bundleForClass:viewControllerClass];
UIStoryboard *storyboard =
[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:classBundle];
MyViewController *viewController =
[storyboard instantiateViewControllerWithIdentifier:className];
(This all assumes that your nib names and storyboard identifiers match the class names. If they don’t, change it.)
"AViewController" without any controls initialised
is because the initialisation of all these controls is belong to view, you need to call [viewController loadView] to init the UI component.
if you also use viewDidLoad func to init some UI component, you must call [viewController view] to trigger viewDidLoad function.

UIViewControllerHierarchyInconsistency when trying to present a modal view controller

Trying to present a modal view controller with the following code
MapViewController *mapView = [[MapViewController alloc] initWithNibName:#"MapViewController" bundle:nil];
mapView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self.navigationController presentModalViewController:mapView animated:YES];
[mapView release];
Keep getting the following error..
'UIViewControllerHierarchyInconsistency', reason: 'A view can only be associated with at most one view controller at a time! View <UIView: 0x1ed815a0; frame = (0 20; 320 460); autoresize = W+H; layer = <CALayer: 0x1ed81600>> is associated with <UIViewController: 0x1ed835a0>. Clear this association before associating this view with <MapViewController: 0x1dd947c0>.'
This is an old project that I havent touched in months, wonder what could cause such an error?
This happened to me already twice in the newest Xcode release.
In both cases I needed to make changes to the UIViewController's XIB file (In you case it would be MapViewController.xib:
BEFORE:
Move main View out of View Controller's children:
Remove View Controller from the XIB (it is not necessary since File's Owner should be of its Class already):
AFTER:
I had this problem when running Apple's example audio app MixerHost on the iOS 6 simulator.
The equivalent of the above fix, namely to edit the supplied MixerHostViewController.xib by dragging the View object to the top level, and discarding the now-empty ViewController that used to contain it, worked perfectly (though not before I'd spent hours working out what the underlying problem was, so I'm feeling done-over by Apple at the moment - seems they tightened something up but didn't bother to check if it broke their sample apps).
I had this problem when my Nib had a UIViewController in the file at top level. So loading from Nib created that UIViewController, then I tried to use it from my class, which was in the position of MapViewController in your code.
In my case the solution was simply to remove the UIViewController from my Nib file.
You should do it like this..
MapViewController *mapView = [[MapViewController alloc] initWithNibName:#"MapViewController" bundle:nil];
UINavigationController *navCntrlr = [[UINavigationController alloc] initWithRootViewController:mapView];
mapView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//hide navigation bar if needed
[self.navigationController presentModalViewController:navCntrlr animated:YES];
[mapView release];
Maybe in some cases it is better to take another approach and not delete the UIViewController from the NIB, because, for one thing, by removing the view controller from the NIB's hierarchy, you lose the Auto Layout margins.
Why not just leave the UIViewController in your nib (.xib) and create an outlet for it in the file owner class? Then, rather than instantiate the view controller directly in you code, load the nib with the UINib class, and, at the optimal time (from the memory/resource usage standpoint), invoke the nib instance's instantiateWithOwner() method to unarchive NIB and connect the nib objects to the owner class's outlets.
#IBOutlet var myViewController: myViewController?
var nib : UINib?
nib = UINib(nibName: "TheNib", bundle: nil)
if (nib == nil) {
println("could not load nib: TheNib.xib")
}
nib!.instantiateWithOwner(self, options: nil)

Resources