I'm doing some iPhone development, and I'm using Storyboards to mock up and expedite my development.
I didn't came from the conventional way of doing things, do I have to?
Anyway, I have storyboard,
TableViewController
NavigationController->ViewController->TabViewController [
AnotherViewController
I wanted to add a new ViewController attached to the TableViewController so that when I click on the row item it will show it on the other view, however;
I can't find a way how to connect the new ViewController into the TableViewController (vice versa)
So I tried the conventional way of doing things on the
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
I put the ff:
CViewController *controller = [[CViewController alloc] initWithNibName:????? bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
I tried to give the Controller an identifier on the Attributes Inspector but does not work and is giving me the following crash stack:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/paulvincentong/Library/Application Support/iPhone Simulator/5.1/Applications/A1C369F8-9EAD-4794-8861-945C73F7FE0B/SyncProto.app> (loaded)' with name 'ControllerViewName'
If I remove the Identifier, I'll get a no NibName exception;
What should I do? I know it should just be the same as I was able to go as far as four levels of relating controllers, there might be something at the back of my head that is confusing me...
TIA,
try this in your cellForRow
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard"
bundle:nil];
ViewCont * view = (ViewCont *) [storyboard
instantiateViewControllerWithIdentifier:#"view"];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self view animated:YES completion:nil];
}
Make sure you have set your storyboard also in the project manager.
Are u using IB? There you can drag directly.
Otherwise in storyboards you don't use the push method you stated. You use performSegueWithIdentifier. Storyboards are about segues. You can segue directly or use target actions.
Again the strength of storyboards is in their visual representation. Use IB.
Otherwise you might also consider delegation (ESP for ipad).
After playing around... I found the suitable answer to my question;
My problem appears to be cause of
Confusion - a new programmer's dilemma.. tho the question is a common one, we can never really deviate if its really the same with those already existing and asked before only up until we tried it ourselves and found out that it really was.
The solution could vary from case to case; and for me I tried to do the ff:
Approach 1: (using the "instantiateViewControllerWithIdentifier") with a segue arrow
Create the view to be added
Position your mouse pointer to the Nib element source view controller you want to trigger the segue then hold control
Drag you mouse to the destination view controller
A popup will appear, choose your segue type (push, modal, custom) then automatically xcode will create the necessary connections
Select your destination view controller and on the Attribute Inspector there is a Collapsible group with Identifier field -> on this field you will put your custom identifier for the view
So the source code would look like;
ViewController *view = [self.storyboard instantiateViewControllerWithIdentifier:#"CustomViewName"];
[self.navigationController pushViewController:view animated:YES];
Approach 2: (using the "instantiateViewControllerWithIdentifier") without the segue arrow
Create the view to be added
Provide the new controller with the necessary identifier then you're good to go
Using the same source as defined above
However, using this approach will break your storyboard's consistency and why use this? (still something I have to find out), its not obvious when you start looking for the segue arrow that was never there, albeit it works.
This code will not work on the basis that I don't have a nib with a name ????,
CViewController *controller = [[CViewController alloc] initWithNibName:????? bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
and since its on a storyboard and assuming everything was done using the storyboard, then time to forget about the nibName because it will never happen..
Hope that this idea would help a few...
Learning is a thorough process yet its a very interesting thing to do...
Thanks.
Related
I am trying to convert my App to a Storyboard, but am having some problems.
In de previous model I could have an 'actionClass' in my AppDelegate which I called when I needed to pop-up a view.
E.g.
DOArticleViewController *articleView = [[DOArticleViewController alloc] initWithArticle:article notification: notification nibName:#"DOArticleViewController" bundle:nil];
[[self navigationController] pushViewController:articleView animated:YES];
But now with the storyboard it does not work anymore.
Then I tried the following code in the AppDelegate:
id currentController = [[[[self window] rootViewController] navigationController] visibleViewController];
[currentController performSegueWithIdentifier:#"settingsSeque" sender:nil];
Don;t think this is the best anyway, as only the rootViewController has all the seques needed, and might not be the visibleViewController, but one step at a time.
With this the only thing I see happening is the message and no action:
Unbalanced calls to begin/end appearance transitions for UINavigationController: 0xb428e00.
I spend a view hours now on trying to figure out to get this to work, but am realising that it might be better to go back to the traditional independent XIB files....
I solved with the answer given in this question: ios: Accessing a navigation controller from app delegate
I tried to get the Navigation Controller, but this was nil and I didn't realise it.
My navigation controller was the rootViewController, so that is also the NavigationController.
Casting the rootViewController to NavigationController and invoking 'visibleViewController' worked fine after that!
this question is very frequent, but I am not able to solve it with any answers available.
I am working on iOS 5.1. My navigation controller is one tab amongst tab bar view controllers. There's a tableview, in which selecting of a row pushes new view controllers.
This problem occurs Only on selecting of the second row and only sometimes. It's not regular.
The Pushed view comes blank - viewWillAppear/viewDidAppear are not being called. On clicking the back button of the navigation bar - the root view's viewWillAppear/viewDidAppear are also not being called, making it blank.
I am pushing the view on select of first row/second row in exactly the same way. But the problem occurs only on the second row.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
switch (indexPath.row) {
case 0:
AViewController *aObj = [[AViewController alloc] init];
aObj.homeObj = self;
[self.navigationController pushViewController:aObj animated:YES];
[aObj release];
break;
case 1:
BViewController *bVCObj = [[BViewController alloc] init];
bVCObj.homeObj = self;
[self.navigationController pushViewController:bVCObj animated:YES];
[bVCObj release];
break;
default:
break;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I have tried this and this but in vain.
viewDidLoad is being called on pushing the BViewController, However, viewWillAppear and viewDidAppear is not being called. Following is my viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
NSLog(#"nav stack: %#", [self.navigationController viewControllers]);
NSLog(#"nav stack: %#", [[self.navigationController visibleViewController] description]);
//some initialization and call of methods
}
It's not regular. Sometimes I get this scenario, and this continues until I close the app from the background and restart it. But sometimes it works just fine. I am just pushing my view controller to the nab stack.
As I mentioned in the comment, It's a regular navigation controller in tab bar controller.
How are you defining your views for AViewController and BViewController? Generally you'd use initWithNibName, e.g.
AViewController *aObj = [[AViewController alloc] initWithNibName:#"mynibname" bundle:nil]`
As Carl pointed out, you can apparently use just init (though I don't see this documented in the UIViewController Class Reference), but then the system will be very particular about the name of your NIB file. The documentation does say, though, that you can use initWithNibName and pass a nil for the NIB name, in which case it will try to find it for you. Personally, if you're having inconsistent results, though, I'd try using initWithNibName and explicitly pass the name of your NIB, and see if that rectifies the situation.
Or are you building your view programmatically with loadView in your two controllers? Then you need to show us those loadView routines (not to be confused with viewDidLoad).
But according to the documentation, you need to either specify your NIB or use loadView. See the View Management discussion in the UIViewController Class Reference.
Update:
Given your feedback, I have a couple of thoughts:
Needless to say, the problem is apparently not related to the above code. You need to broaden you search and show us more code. Perhaps show us your viewDidLoad of B?
Generally when you don't get these sorts of events, it's because the view controller hierarchy has gotten out of sync with the view hierarchy. The most common way that people do this is if they've done something like "[addSubview someNewController.view]" at some point. If you're using a view controller in any context either than (a) your app delegate's initial configuration; (b) presentViewController (or dismiss); or (c) pushViewController (or pop), then you might want to share what you've done.
As andreamazz pointed out, your comment, "My navigation controller is inside a view controller of the tab bar controller," is a little disturbing if one reads it literally. You can put navigation bar in a view controller's view, but you can't put a navigation controller in a view controller (unless you're doing view controller containment, which is a whole different beast). Equally concerning is where, in another one of your questions, you said, "Embedding a UINavigationController or UITabBarController (my case) in a UIViewController somehow interrupts with the calling of these methods." Thing is, you don't embed nav controllers in other view controllers (unless it is, itself, a container controller such as a tab view controller), but rather its the other way around. But if you literally mean that you have a controller that contains a nav controller, you have to show us how you're doing that (proper view controller containment?) because that's highly unusual.
It's unusual, but I've had projects get corrupted, ending up in weird states. At a minimum, I might suggest "Product" - "Clean" and rebuild. If problem persists, and you've isolated the problem to to B's NIB, then temporarily rename the it and build a quick and dirty one from scratch.
I call a View to be presented with the following code:
#import "infoView.h"
...
infoView *viewInfo = [[infoView alloc] initWithNibName:nil bundle:nil];
viewInfo.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewInfo animated:YES];
But when it is presented in run-time the view that is loaded turns out black.
Currently I am using storyboard, but I need to use this code, for it is a lot more efficient in my case, because I am dealing with multiple views!
It works fine if I connect it via StoryBoard.
I should be seeing 2 labels, 1 UITextView, and 2 UIButton.
The view was created using StoryBoard, when the .m and .h files for the view where created I did not add a .xib for it. And also it is linked through the "Custom Class" section in StoryBoard.
Thanks, hope someone can help!
It's generally pretty bad form to mock people who are taking the time and effort to help you.
Naming is important it makes your code easier to work with and allows other people to use it. Not following the conventions for the language you are working in is dangerous and means that your code is not compatible with other developers as things are interpreted differently.
If you look at the docuemntation for UIViewController you'll see this note in the initWithNibName:bundle: method description
If your app uses a storyboard to define a view controller and its associated views, your app never initializes objects of that class directly. Instead, view controllers are either instantiated by the storyboard—either automatically by iOS when a segue is triggered or programmatically when your app calls the storyboard object’s instantiateViewControllerWithIdentifier: method. When instantiating a view controller from a storyboard, iOS initializes the new view controller by calling its initWithCoder: method instead. iOS automatically sets the nibName property to a nib file stored inside the storyboard.
Therefore you are instantiating your controller wrong, the storyboard should be instantiating it. Which is done like this (naming corrected)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle bundleForClass:[self class]]];
InfoViewController *infoViewController = [storyboard instantiateViewControllerWithIdentifier:#"InfoViewController"];
infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self infoViewController animated:YES];
Side note
infoView is a bad name for the class not only because you didn't start with a capital but also because it's completely deceiving. Anyone reading this would assume that InfoView is a subclass of UIView not UIViewController.
I'm programming a complex storyboard application and I'm encountering some issues when it comes to code re-use across view controllers and different application paths.
Can I segue to a ViewController that is not directly connected to the current one?
How do I segue out from a button to several ViewControllers conditionally? Connecting both does not work.
Can I enter the ViewController sequence from an arbitrary position in the application?
Just a few questions that come up. Anybody have any ideas or good examples?
Can I segue to a ViewController that is not directly connected to the current one?
Not with a segue. But you can push or present a viewController from a storyboard modally, like you did with .xib files.
// if self was created from code or from a .xib:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"MainStoryBoard" bundle:nil];
// if self was instantiated from within a storyboard:
UIStoryboard *storyBoard = self.storyboard;
MyFancyViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"MyFancyViewControllerIdentifier"];
[self presentModalViewController:viewController animated:YES];
But you have to set the identifier first. Select the viewController in the storyboard and do that in the attributes inspector.
Once the MyFancyViewController is visible you can use all its segues. It might feel strange to switch between code and storyboard segues, but there is nothing wrong with that. It makes the whole storyboard thing really usable.
How do I segue out from a button to several ViewControllers conditionally? Connecting both does not work.
Add two or more segues that start from the viewController (not from a button or any other view. E.g. start your control-drag at the statusbar) to the target viewControllers. Set identifiers for them and use some code like this:
if (someState) {
[self performSegueWithIdentifier:#"MyFirstSegueIdentifier" sender:somethingOrNil];
}
else {
[self performSegueWithIdentifier:#"MySecondSegueIdentifier" sender:somethingOrNil];
}
Can I enter the ViewController sequence from an arbitrary position in the application?
Yes, if you use "old school" view controller management. Similar to the first part. Instantiate your viewController and present it with code.
I'm new to iPhone Development and I did some examples and seen code and code and more code but I still can't get the
when the user taps here show this view using this animation, and go back after (user taps a back button)
I did some Tab Bar examples, Utility examples, etc but when I start a project from scratch the code never does what I want :-/
every time I create a View (xib) I also create the controller (h and m files), as all examples are like this, and I have no idea if I can only create 4 Views and just have one controller :-(
when a user taps a UITableCell how can I load a new view using an animation? and how can I go back to the UITableCell the user was?
kind'a (in C#)
myNewForm f = new myNewForm();
f.show();
...
this.Close();
If someone can share some knowledge or a tutorial or a screencast, I will greatly appreciate
Thank you!
Tap a cell and show a new view, if your table view has a UINavigationBar:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == myRow) {
MyViewController *vc = [[MyViewController alloc] init];
[self.navigationController pushViewController:uvc animated:YES];
[vc release];
}
}
Then the user can tap back as well. You can present modally as well, but would need to implement a way to return to the table view, by using:
[self presentModalViewController:vc animated:YES];
But the simplest base case is this, which you can see used in any template app's AppDelegate:
[window addSubview:vc.view];
Remember that the OS is doing a lot for you, including teaching you about MVC by encouraging the creating of controller classes.
You want to read about UINavigationController. Maybe also read the "View Programming Guide for iPhone OS", all available at http://developer.apple.com.