I'm looking how to make a start button in storyboards, but it hasnt the initwithnib code to use, like in XLB. I'm using the sprite kit. So far my code is like this.
Viewcontroller.h = mainmenu
#interface ViewController : UIViewController
- (IBAction)PlayBtn:(id)sender;
#end
And in the viewcontroller.m I want to connect it to myScene where the game is. In the myScene.m.
for that I tried using following.
- (IBAction)PlayBtn:(id)sender {
MyScene *game = [[MyScene alloc] initWithNibName:nil bundle:nil];
[self presentViewController:game animated:YES completion:NULL];
}
Although getting error at the initWithNibName doesnt exist. I have only used xlb before but wanted to make a game with sprite-kit.
Here is a screenshot of my storyboard. All graphics are copyrigth protected.
Cheers!
You can mix and match nib files and scenes from storyboards if you like. If you want to do that, create a nibfile (XIB file) and save it to your project. Then use initWithNibName:bundle: as always.
If you haven't created a nib, that won't work.
If you want to load your view controller scene from your storyboard you have a couple of options.
You can set up a segue by control-dragging from your current view controller to another view controller, naming the segue with a unique identifier, and then invoking the segue directly using the view controller method performSegueWithIdentifier:sender:
Another option is to give the scene itself a unique identifier, then instantiate it with instantiateViewControllerWithIdentifier:, and display it using presentViewController:animated:completion: just like you are trying to do now.
Related
Hey guys I'm trying to get my app to load a new view when a certain method is called. Inside the method I have the code:
ViewController *GameOverViewController = [[ViewController alloc] init];
[self presentViewController:GameOverViewController animated:YES completion:nil];
which is taken straight from How to switch views programmatically in a ViewController? (XCode iPhone).
Anyways, when I try to switch from my view controller called Game to a view controller called GameOverViewController I just get a ton of errors. Mainly
"Unknown receiver 'ViewController'; did you mean 'UIViewController'
And my app crashes. I'm obviously doing something wrong but I have no idea what that is exactly. Do I have to declare the GameOverViewController in my Game.h or in my appDelegate or something?
EDIT: Both view controllers are in the same main.Storyboard file if that matters
The unknown receiver message means that it can't find the class definition for the view controller class called ViewController. Is that really the name of the class you're using for your "game over" view controller? And if so, have you done the #import "ViewController.h" at the start of this .m file?
The fundamental problem is that it cannot find the class called ViewController.
Setting that aside, we don't generally instantiate new view controllers using alloc and init anymore, as that answer may have implied. That was a technique used with NIBs (and only worked if the NIB name matched the class name).
For new developers, I might encourage you to start with storyboards. Any modern tutorial should walk you through how to use storyboards. (Google "iOS storyboard tutorial" and you'll probably get lots of hits.)
If, for example, your storyboard has a scene with a "storyboard identifier" of GameOverViewController, then you might programmatically instantiate it and present it with something like:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"GameOverViewController"];
[self presentViewController:controller animated:YES completion:nil];
Or, if your storyboard had a segue from the current scene to the next scene, you'd make sure that segue had its own storyboard identifier, e.g. GameOverSegue, and then you'd perform it like so:
[self performSegueWithIdentifier:#"GameOverSegue" sender:self];
But find yourself a good introduction/tutorial on storyboards, as stumbling through Stack Overflow for answers will not be a very fruitful exercise.
For historical purposes, it's worth noting that if you were using NIBs, you can use the construct you referenced to in your question (but you'd have to make sure that (a) the class name was right; and (b) you did the #import that class header). And if the destination NIB had a different name than the class, you'd have to do something like:
UIViewController *controller = [[NSBundle mainBundle] loadNibNamed:#"nibname" owner:self options:nil]`;
[self presentViewController:controller animated:YES completion:nil];
But this is all academic unless you're using NIBs. If using storyboards, use one of the above patterns if you need to transition to a new scene programmatically.
You are in over your head. You should slow down and do some more studying or things are going to crash all over the place. I suggest going through a good book on iOS development and doing the exercises.
On to your question:
In the code you posted you're using a class "ViewController". There is no system-defined class "ViewController", although it is a common class name in example projects, and I think some of the project templates in Xcode even create a root view controller with that class name.
The name you give to your variable ("GameOverViewController" in the code above) is local and not really important. That's just a variable name. You can rename it lateForDinner if you want to, and it won't make any difference as long as you change that name everywhere in the scope in which it's defined.
The fact that you're being told that the class "ViewController" is unknown suggests that it hasn't been defined anywhere in your program.
You need an #interface and #implementation section that defines the ViewController class. Usually those will be in files called ViewController.h and ViewController.m, respectively. They might look something like this:
//ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController: UIViewController //Defines it as a subclass of UIViewController
// properties and methods of ViewController defined here
#end
And the .m file:
//ViewController.m
#implementation ViewController
// Implementation of ViewController methods go here.
#end
It's also possible to include the interfaces of multiple classes in a single header file, and the implementations of multiple classes in a single .m file, although I dislike this practice intensely. Keep it simple - one class per .h/.m file pair, with the file names identical to the class name.
I have a multi-player game where I want it to start after I press a button in the menu. The problem is I don't know how to transit from the menu to the game directly after I start multiplayer.
In ViewController.m
- (IBAction)multiplayer:(id)sender {
[Nextpeer launchDashboard];
}
In AppDelegate.m
-(void)nextpeerDidTournamentStartWithDetails:(NPTournamentStartDataContainer *)tournamentContainer {
UIStoryboard *storyboard = self.storyboard;
ArcadeView *svc = [storyboard instantiateViewControllerWithIdentifier:#"arcade"];
[self presentViewController:svc animated:YES completion:nil];
srandom(tournamentContainer.tournamentRandomSeed);
[tournamentContainer tournamentIsGameControlled];
}
I'm getting the error of
"Property'storyboard'not found on object of type 'AppDelegate *' and
"No visible #interface for 'AppDelegate' declares the selector
'presentViewController:animated:completion:'"
How do I change from one ViewController to another ViewController using storyboard?
Normally in cocos2d, I would do like this:
CCScene *gameplayScene = [CCBReader loadAsScene:#"GamePlay"];
[[CCDirector sharedDirector] replaceScene:gameplayScene];
What's the equivalent?
How do i change from one ViewController to another ViewController using storyboard?
Typically, you'd use a segue to switch from one view controller to another. You can create a segue in your storyboard, connect it to a button, and the button will automatically trigger the segue and transition to the next view controller. As part of the segue process, the existing view controller will get a chance to "prepare" for the segue, at which point it can clean up after itself as necessary and also provide any information that the next view controller might need. Read all about it in the docs for -[UIViewController prepareForSegue:sender:].
There are a number of different ways that you can transition from one view controller to another, of course. You can push a new view controller onto a navigation stack, have a tab bar controller switch between several view controllers, present a view controller, simply remove one view controller's view hierarchy from the window and install the new one, and so on. Many of the possible transitions are provided by existing segue types, but you can also create your own custom transitions by creating your own segues.
If all this is new to you, you should probably spend some time reading through View Controller Programming Guide for iOS.
One of the things I don't like about WYSIWYG/visual programming, is when you get to a point where you need to step outside of the box, you're left scratching your head. I'm at such a point right now along my iOS learning curve.
I have a custom UICollectionView thing. In two places (create and edit points), I need to present a list to the user to enable/disable (select/deselect) items from a list. So I go to the storyboard and whip up something like this:
In the past, following tutorials, I would control-drag a link from some control to the NavigationController show in the middle, I would tell it was a modal segue, tune a couple of methods, and get an arrow connecting the two for my efforts.
But in this case, I don't have obvious points to start that action from. I do have a + button. But it needs to do some other things first, and if all is well, then programmatically initiate the open, and somehow get notified of the state when it returns. Same for the individual cells, they might want to configure my table controller, and then open it, and be notified when it closes.
So I'm looking for a recipe of how one does this, what the key methods I should be looking for are. Apple's docs are great for reference, but I find figuring out how to do something from scratch difficult.
After creating a segue in your storyboard, you can initiate a segue any time programmatically by calling
[self performSegueWithIdentifier:#"segueID" sender:person];
Where "segueID" is a string you set for your segue in interface builder in the Identifier field in the identity inspector (right menu panel, 4th tab).
The segue does not need to be created from a control, you can just create one directly from one view controller to another. I usually do this on the right side menu by right-clicking on one view controller object and dragging to another one. This way, it acts as a segue that you can initiate programmatically any time you want.
As for getting notified when you come back to a view controller, (unless I'm misunderstanding your question) you can use either:
(void)viewWillAppear:(BOOL)animated
(void)viewDidAppear:(BOOL)animated
Create a UINavigationController programmatically with a desired view controller set as a root view controller. Here is an example of what you could put in a method invoked when user taps the plus button:
UIViewController *vc = [[UIStoryboard storyboardWithName:#"YourStoryboardName" bundle:nil] instantiateViewControllerWithIdentifier:#"YourViewControllerID"];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:nc
animated:YES completion:nil];
To get a state, or information about the selected items you can use Delegation and declare a protocol. Example:
#protocol YourSampleDelegate <NSObject>
- (void)didSelectItem:(NSObject *)item;
#end
Then, your view controller (the one with the plus sign) should implement this protocol:
#interface ViewController : UIViewController<YourSampleDelegate>
...
#end
#implementation ViewController
...
#pragma mark - YourSampleDelegate conformance
- (void)didSelectItem:(NSObject *)item;
{
// Do something with the item.
}
#end
You also have to create a delegate property in a view controller with collection view and set the view controller with a plus as a delegate. There are tons of examples on the Internet. I hope this shows you the right direction.
I'm making an app that will have a VC doing a similar job as a UITabBarController and I'm using
[self addChildViewController:theViewController];
// [self addSubview ... etc
to put a custom UIViewController's view as a subview of my main (root) VC.
So my question is, which is the correct way to instantiate a VC and not have to build it's UI programatically - from a .xib file, or from a storyboard?
With a xib:
UICustomViewController *controller = [[UICustomViewController alloc] initWithNibName:#"customVC" bundle:nil];
With a storyboard:
UICustomViewController* child = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
I believe .xib files are old stuff and storyboards are the way to go, but I also read this article, which suggests that using a storyboard to do this is a bit hacky. I don't know, any thoughts?
there is nothing any major difference in both way , they are same . but in many other angle storyboard is the straight way, there is nothing any hacky
If you want the child view controller to be present when the app opens, you can do it in a storyboard without any code at all. Add a container view to your root vc, and you will automatically get a view controller embedded in it.
My objective is to create a tabbed application, then the view for each of the tabs are constructed in separate storyboards.
My mainstoryboard is a tab view.
Then I create a secondary storyboard (storyboard#2) with 2 View Controllers. The first view controller (also ticked as initial) have a button, and segue (modal) to 2nd view.
I managed to load the view by subclassing and overriding loadView from storyboard#2.
Here's the simulator output.
When click on the "click me" button, I get a EXC_BAD_ACCESS. The segue does not work, seems like the second storyboard is not being loaded completely.
Has anyone tried to do this before and get it working? There's a youtube video from SkillMaster.net but he does not demonstrate if a segue is working under the secondary storyboard. the video is here: http://youtu.be/D4_twoYvB4M
Thanks for any input and help!
Screenshots:
http://www.box.com/s/njnyzjoqg8pnqofv838m
http://www.box.com/s/8dqygclmp5ic86e47bi5
http://www.box.com/s/k7foe7gpgh2rs3y8gqxd
http://www.box.com/s/rym111x7xqxqao51ruip
These are the best articles I've seen on multiple storyboards.
Storyboard best practices
Linking storyboards with segues
Not only does this guy tell you how to create a new storyboard in code, he
recommends multiple storyboards in practice (more modular code)
discusses when to use xibs vs storyboards (xibs hold views, storboards are based on controllers)
provides a class for linking storyboards with segues on github
Note that this last point is important because the key downside of multiple storyboards is that you can't usually link them with segues, but robs library allows that with a bit of fudging
Also see the discussed here
The OP edited his question to include the answer:
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"HelpStoryboard" bundle:nil];
UIViewController* initialHelpView = [storyboard instantiateInitialViewController];
initialHelpView.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:initialHelpView animated:YES];
Of course, where you call this from is meaningful, because you might have 2 storyboards and their view stack in memory. So probably best if you call this code from outside the other storyboard's view controllers.
I've examined the RBStoryboardLink approach suggested by Rhubarb.
This implementation substitutes view controller's properties which looks odd. I believe I've found the way to avoid this. Here is the demo project.
Navigation controllers
Navigation controllers could just set a referenced view controller as a root. Implementation of such view controller may look like this:
#interface ExternNavigationController : UINavigationController
#property (strong, nonatomic) NSString *storyboardName;
#property (strong, nonatomic) NSString *sceneIdentifier;
#end
#implementation ExternNavigationController
- (void)awakeFromNib
{
NSAssert(self.storyboardName, #"storyboardName is required");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:self.storyboardName bundle:nil];
UIViewController *vc = self.sceneIdentifier
? [storyboard instantiateViewControllerWithIdentifier:self.sceneIdentifier]
: [storyboard instantiateInitialViewController];
self.viewControllers = #[vc];
}
#end
View controllers
Problems begin when you want to push a view controller defined in an external storyboard. This is the case when properties are copied. Instead of this, we can implement a custom segue which will substitute a fake destination controller with a real one from external storyboard.
#interface ExternStoryboardSegue : UIStoryboardSegue
#end
#implementation ExternStoryboardSegue
- (id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(ExternViewController *)destination
{
NSAssert(destination.storyboardName, #"storyboardName is required");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:destination.storyboardName bundle:nil];
UIViewController *vc = destination.sceneIdentifier
? [storyboard instantiateViewControllerWithIdentifier:destination.sceneIdentifier]
: [storyboard instantiateInitialViewController];
return [super initWithIdentifier:identifier source:source destination:vc];
}
- (void)perform
{
[[self.sourceViewController navigationController] pushViewController:self.destinationViewController animated:YES];
}
#end
ExternViewController is used as a placeholder and contains required for substitution properties (storyboardName and sceneIdentifier).
#interface ExternViewController : UIViewController
#property (strong, nonatomic) NSString *storyboardName;
#property (strong, nonatomic) NSString *sceneIdentifier;
#end
#implementation ExternViewController
#end
We need to set these properties and custom class for placeholder view controller. And also link view controller with ExternStoryboardSegue.
From one of my XIB files I am navigating into a more complicated part of the GUI, and for this part I am using a Storyboard. So a button in my XIB will navigate to the storyboard. The code I have for this is:
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MyStoryboardIdentifier" bundle:nil];
UIViewController* myStoryBoardInitialViewController = [storyboard instantiateInitialViewController];
[self.navigationController pushViewController:myStoryBoardInitialViewController animated:YES];
This will successfully push my StoryBoard onto the view. The code above is called from a buttons "Touch Up Inside" action.
As from Xcode 7(and ported back to iOS8) you can now have storyboard references. It was mentioned in this WWDC 2015 session(it starts talking about them around first hour). Basically all you had to do is select ViewController's which you wish to move to separate storyboard, and click on Editor->Refactor to Storyboard.... Give it a name and voila:
Please note that if you had VC's which are moved to the new storyboard, and are not referenced outside of it(what it should be), you should delete their references from main.storyboard(relax they will remain in newly created storyboard, you are deleting only references to them).
Apple's docs say that you may have multiple storyboards. Unfortunately they don't go into any real detail on how to do that. As you've found out, Interface Builder won't help you, so you'll have to do it in code. It works much like loading XIBs:
[UIStoryboard storyboardWithName:#”MyNewStoryboard” bundle:myBundle]
Having said that, if you don't "want one big/bloated storyboard" as you said in your comment then XIBs really are the way to go. That 'bigness' is the benefit: all the transitions between VCs are laid out in one place. Having multiple storyboards is really so that you can support multiple different and unrelated flows through your app: for example, one storyboard for a complex configuration flow and another one for the main user flow.
Xcode 8.2.1
You can reference a view controller in an external storyboard.
drag a connection from the UITabBarController to the external Storyboard Reference, add it as a "view controllers" relationship. In the main storyboard it shows as "Item/square", but in the external storyboard you should add a UITabBarItem and define the name and image/s for the tab.
Attributes inspector when the Storyboard Reference is selected.
You will also need to give the external controller a "Storyboard ID" in its storyboard (not shown here), and reference it's name in the reference.
I've found that if you have a named segue in a second storyboard that you want to use in a call to performSegueWithIdenitfier: you must set the "Storyboard ID" field in the "Identity" tab on the source ViewController.
For example if you gave a VC called "ViewController1" with a segue called "segue1" to another VC, set the "Storyboard ID" of "ViewController1" to whatever (say "viewC1" or something) and then in ViewController1.m you can use [self performSegueWithIdentifier:#"segue1" sender:self].
Follow below steps to achieve this task:
Step 1 : Search for an Storyboard Reference in components (Refer Screen Shot)
Step 2 : Select new storyboard reference. (Refer Screen Shot)
Step 3: Provide new storyboard name and identifier of initial view controller's identifier (Refer Screen Shot)
Build and Run. It will Work.