I am using a storyboard to switch between views. Pretty simple, until I try to add ECSlidingViewController.
If I add the above slide menu to the first view I call using this:
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
If I set #"Main" to #"Speakers", the view loads just fine. I get the slide menu and everything. #"Main" also loads just fine.
However, if I load #"Main" first like in the code above, then switch views to the one I've designated "Speakers", it crashes as soon as I try to call the slide menu with this code:
if(![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
I get a crash stating: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
I have tried switching views numerous ways.
I've tried:
SpeakersView *second= [self.storyboard instantiateViewControllerWithIdentifier:#"Speakers"];
[self presentViewController:second animated:YES completion:nil];
I've tried:
SpeakersView *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"Speakers"];
[self presentViewController:svc animated:YES completion:nil];
Each one works just fine if I don't call up the slide menu, but each causes a crash when I do add the slide gesture.
Ideas?
Okay, I figured it out. After a long, arduous experience, I figured it out.
So I've got numerous files (.m and .h for each):
InitViewController
MenuViewController
MainViewController
SpeakersView
The objective was to switch from MainViewController using a button not on the slide menu to SpeakersView, but doing it directly caused the slide menu to be null, as was pointed out by Phillip Mills.
Instead, I put this in InitViewController.h, right underneath #Interface:
#property (nonatomic, retain) NSString *location;
Then this under #implementation in InitViewController.m:
#synthesize location;
I originally had this under ViewDidLoad in InitViewController.m:
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
I changed it to this:
if([location length] == 0){location = #"Main";}
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:location];
That way if the variable was empty, it defaulted to #"Main".
Then in MainView.m, where I execute the code after pressing the button, I have this:
InitViewController *ini;
ini = [self.storyboard instantiateViewControllerWithIdentifier:#"Init"];
ini.location = #"Speakers";
And voilà, the view switches just fine to Speakers. More accurately, it switches to InitViewController which automatically switches to Speakers or whatever I set location to.
Thanks to everyone for your help.
Related
UPDATED FOR COMMENTS
I am trying to make this code work, but whenever I press the "nextButton", the program ends and I cannot figure out what went wrong. Can you please look at my code and figure out if anything is wrong.
- (void)viewDidLoad {
[super viewDidLoad];
Player1.placeholder = #"Player 1";
Player2.placeholder = #"Player 2";
Notes1.placeholder = #"Notes";
Notes2.placeholder = #"Notes";
[nextButton setAction:#selector(nextButtonPressed:)];
}
-(IBAction)nextButtonPressed:(id)sender {
if ([self.delegateP respondsToSelector: #selector(addPlayerViewController:didFinishEnteringPlayer1:didFinishEneteringPlayer2:)]) {
[self.delegateP addPlayerViewController:self didFinishEnteringPlayer1:Player1.text didFinishEneteringPlayer2:Player2.text];
NSLog(#"Works");
}
[self performSelector:#selector(nextButtonPressed:) withObject:nil afterDelay:0.25];
}
I also have another question to do with this code. To pass information through different view controllers using delegates, do you have to use a button or a bar button item?
The error that is displaying:
-[UIStoryboardPushSegueTemplate nextButtonPressed:]: unrecognized selector sent to instance
First you can´t put both lines:
[self presentModalViewController:gameDetails animated:YES];
[self.navigationController pushViewController: gameDetails animated:YES];
Second go to your viewController PlayersViewController and click in storyboard click on editor (top menú XCode) Embed In > Navigation Controller now you with your code change the next lines:
-(void) nextButtonPressed {
NSLog(#"Hi my friend");
[self performSegueWithIdentifier:#"YOUR_SEGUE_NAME_HERE" sender:#"hi"];}
And create new function:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:sender];
}}
The ViewController "YourViewController.h :
#interface YourViewController : UIViewController
#property (nonatomic, strong) NSString *MyObjectHere;
#end
Try setting a symbolic breakpoint on all Objective-C exceptions and see if that gives you your crash line numbers and error messages again.
The code you posted for setting up the target/action on your bar button item looks correct.
Edit: Disregard this part about changing the selector.
(I'm leaving it for continuity, but ignore it.)
One thing you might try is changing the selector to
:#selector(nextButtonPressed:) (Colon added)
And then adding the button as a parameter to your action method:
-(IBAction) nextButtonPressed: (UIButton *) sender
Action methods should work with or without the sender parameter, but
it's worth trying.
(Also you should add the IBAction keyword for clarity even if you're not hooking up the action in IB.)
EDIT: rmaddy pointed out that your code is trying to both modally present and push the same view controller. Don't do that. Do one thing or the other.
You should use either
[self presentModalViewController:gameDetails animated:YES];
(To present it as a modal)
or
[self.navigationController pushViewController: gameDetails animated:YES];
(To push it onto the navigation stack.
But not both. Doing both is almost certainly the cause of your crash.
i'm a new developper with storyboard.i try to make a app with a slide-out menu.
To do this, i use the library : SWRevealViewController and the tutorial : http://www.appcoda.com/ios-programming-sidebar-navigation-menu/ .
i follow the tutorial, but i load the application, i'have this error :
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '*** -[__NSArrayM
insertObject:atIndex:]: object cannot be nil'
my app crash on this line :
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
how can i set self.revealViewController ?
here my storyboard UPDATED:
to understand my app, startviewController is used to download and store data, after downloading, the mainViewcontroller is showed.
i want my slide out menu on my mainviewcontroller, but i cant not do.
here the code i add to my mainviewController viewdidload :
- (void)viewDidLoad
{
[super viewDidLoad];
self.contentView.autoresizesSubviews = YES;
_sharedUser = [User sharedUser];
///slide out menu
// Change button color
//SWRevealViewController *revealViewController = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"RevealViewController"];
_sidebarButton.tintColor = [UIColor redColor];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
//end slide out
self.contentView.backgroundColor = [UIColor cyanColor];
if (_sharedUser.tokenString) {
}
else{
[self showHomeWithoutLogginView];
}
}
I'm looking at the tutorial you are following. According to your screenshot, there are some stuff missing in your storyboard.
The RevealViewController should be connected with two controllers: a front viewController (for displaying content) and a rear viewController (for showing the navigation menu):
Credits for the image: http://www.appcoda.com/ios-programming-sidebar-navigation-menu/
Those connections (segues) should be marked as "reveal view controller" and each of them have to be named accordingly: "sw_front" and "sw_rear".
Then you have to add the menu items in the navigation menu (rear view controller) and connect each cell to the corresponding viewController, give the segues a name and mark them as a SWRevealViewController class. You may want to connect the front view controller to the viewController you want to be shown first.
I strongly suggest you make the tutorial as it is. I think I used it in the past and it worked pretty well. If you have any doubt about it don't hesitate to ask.
Best of lucks!
SOLVED
thanks to leandro !
here the code who is need in my staviewcontroller who solved my problem:
SWRevealViewController *sideBar = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"SWRevealViewController"];
[self.navigationController pushViewController:sideBar animated:YES];
Are you using the latest version of the SWRevealViewController? The AppCoda tutorial is outdated, and SWReveal has great sample on Git.
Check your segue identifier and class on your storyboard. Have you set sw_front and sw_rear? Also, in the latest version, your segue for setting the Menu / Front View should be: SWRevealViewControllerSegueSetController and not the old SWRevealViewControllerSegue.
EDIT:
Also note that calling [self.revealController panGestureRecognizer]; is enough to enable the gesture; no need for an additional gesture.
EDIT:
Try initializing like this:
MenuViewController *menuVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MenuViewController"];
UINavigationController *frontNavigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"MainNavigationController"];
SWRevealViewController *revealViewController = [[SWRevealViewController alloc] initWithRearViewController:menuVC frontViewController:frontNavigationController];
EDIT:
Can you try adding an action to your Menu Button like this:
[menuButton addTarget:self.revealViewController action:#selector(revealToggle:)
forControlEvents:UIControlEventTouchUpInside];
I am in need of some help please. I have been stuck on this issue all day and I cannot find a fix. I will try and be as clear as possible with my problem.
I have 2 ViewControllers. One is called ViewController and the other is called GameViewController. In the ViewController I have my home screen menu and on the GameViewController I have the Game screen AND the Game Over screen. When you press play from ViewController it takes you to the Game, and then when you die you stay in the same GameViewController but in a Game Over view. If you press restart in the Game Over screen a segue takes you back modally to the Game Screen.
So here is the problem I am having.
When you die for the first time and go to the Game Over screen, you can click on home and it will take you home, BUT if you press restart, then die again (that's twice ) and then try to press home from the Game Over Screen it will NOT run the code inside the home button. The button actually works, I have an NSLog in their and it shows in the debugger screen. Weird I know. Please see below code that will show everything I have done to try and make this work.
In GameViewController.h //Above all the #imports
#class GameViewController;
#protocol GameViewControllerDelegate <NSObject>
-(void) GameViewControllerDidCancel:(GameViewController *)controller;
- (IBAction)homeBtn:(id)sender;
#end
And this just after the the close } in #Interface
#property (nonatomic, weak) id <GameViewControllerDelegate> delegate;
In GameViewController.m after the #Implementation
#synthesize delegate = _delegate;
And this in my homeBtn
- (IBAction)homeBtn:(id)sender {
NSLog(#"home btn pressed");
[self.delegate GameViewControllerDidCancel:self];
}
Then in my ViewController.h
#import "GameViewController.h"
#interface ViewController : UIViewController <GameViewControllerDelegate>
ViewController.m
When I press play
- (IBAction)playButton:(id)sender {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main_iPad"
bundle:nil];
GameViewController* controller= [sb instantiateViewControllerWithIdentifier:#"GML"];
controller.delegate = self;
[self presentViewController:controller animated:NO completion:nil];
[audioPlayer stop];
}else {
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main_iPhone"
bundle:nil];
GameViewController* controller= [sb instantiateViewControllerWithIdentifier:#"GML"];
controller.delegate = self;
[self presentViewController:controller animated:NO completion:nil];
[audioPlayer stop];
}
}
And the method that I try to call from my homeBtn is also in here
#pragma mark - GameViewControllerDelegate
- (void) GameViewControllerDidCancel:(GameViewController *)controller {
[self dismissViewControllerAnimated:NO completion:nil];
}
I am pretty sure that is it. So like I said before, the restart button is just linked to a segue to return back to the Game screen.
Please guys, I am really desperate now, I am completely out of ideas.
Thank you
Quite a convoluted view hierarchy and hard to understand.
What exactly does the restartGameButton do. Is it an unwind segue?
When you press play from ViewController it takes you to the Game, and then when you die you stay in the same GameViewController but in a Game Over view. If you press restart in the Game Over screen a segue takes you back modally to the Game Screen.
What is the GameOver view thing? Once you say its a view in the GameViewController, but then again you say if you press restart a segue takes you back modally to the Game Screen (i.e. GameViewController) which implies the GameOver Screen is also a ViewController.
Why use modal presentation when it is a actually a navigation stack that you want?
Best solution in my opinion:
Make 3 ViewControllers, one for the Start, one for the Game, one for GameOver. Embed the ViewControllers in a navigation controller and push and pop with this one instead of presenting many modal views on top of one another.
These 4 files are relevant to this post:
The FirstViewController has a button (not on the nav bar, a separate button), when it is pressed, the page should curl up to present FilterViewController.
FirstViewController.h
- (IBAction)searchOptions:(id)sender;
FirstViewController.m:
- (IBAction)searchOptions:(id)sender {
FilterViewController *ctrl = [[FilterViewController alloc] initWithNibName:#"FilterViewController" bundle:nil];
[UIView transitionFromView:self.view toView:ctrl.view duration:1 options:UIViewAnimationOptionTransitionCurlUp completion:nil];
[self.navigationController pushViewController:ctrl animated:NO];
}
On FilterViewController it has some UI stuff, you press a button, it saves the UI stuff and then the page curls back down to show the FirstViewController.
FilterViewController.h:
- (IBAction)backToMap:(id)sender;
FilterViewController.m:
- (IBAction)backToMap:(id)sender {
FirstViewController *ctrl = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
[UIView transitionFromView:self.view toView:ctrl.view duration:1 options:UIViewAnimationOptionTransitionCurlDown completion:nil];
[self.navigationController popViewControllerAnimated:YES];
}
The issue here is with the retention of UIView. How can I retain the UIView?
When I click the button on FirstViewController the animation works and the page is presented. However on FilterViewController when I click the button it crashes to the debugger with the error:
EXC_BAD_ACCESS(code=2,address=0x8)
In the output console it says: (lldb)
After the page curl up I have a stepper, when I click the stepper I get the same error in the debugger.
UPDATE: I have tracked the memory location error: http://i.imgur.com/dL18H9Z.png
Thanks.
One thing I notice is that you're pushing a view controller, then pushing another view controller with the syntax "back". This may be the issue: A nav stack is a stack. If you start with view 0, push view 1, if you want to get back to view 0 you "pop" view 1 as opposed to pushing view 0 again.
So in:
- (IBAction)backToMap:(id)sender {
FirstViewController *ctrl = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
[UIView transitionFromView:self.view toView:ctrl.view duration:1 options:UIViewAnimationOptionTransitionCurlDown completion:nil];
[self.navigationController popViewControllerAnimated:YES];
}
The issue here is that you try to make animation between view controllers with UIView's transition method.
According to documentation:
fromView
The starting view for the transition. By default, this view is removed
from its superview as part of the transition.
toView
The ending view for the transition. By default, this view is added
to the superview of fromView as part of the transition.
So, when you call this method, your ViewController's view replaced by another view with animation, and after on stack placed next ViewController without animation, so it's seems like all right (but your first controller's view already replaced).
But when you try to return some error behavior occurs - you replace view of controller, that will be removed.
So, i want to say, that i must be done more carefully, there several different approaches to make custom transition between viewControllers.
For example, you can watch next solution (it's similar to yours) - http://www.vigorouscoding.com/2011/05/custom-uiviewcontroller-transitions/
or
https://gist.github.com/jeksys/1507490
I currently have a button within an app that I am working on, and when I press the button it seems to not call the method when it is pressed. I thought added all the proper code, and wired everything up correctly, but that doesn't seem to be the case.
ViewControllerRootHome.h
#property (weak, nonatomic) IBOutlet UIButton *btndev;
- (IBAction)showDev:(id)sender;
ViewControllerRootHome.m
#synthesize btndev = _btndev;
- (IBAction)showDev:(id)sender {
NSLog(#"dev button pressed");
//dev button pressed
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewControllerDev *dev = (ViewControllerDev *) [storyboard instantiateViewControllerWithIdentifier:#"dev"];
[self presentModalViewController:dev animated:YES];
NSLog(#"dev button press End");
}
The execution is not even reaching the firs log statement in the method.
Things are wired up as such,
On a side note the button that reads "Logs" seems to be loading the scene fine, but for whatever reason "dev" button does not want to call the method / load the scene.
Ohh the source code for everything can be found here, https://github.com/ipatch/KegCop
That button works fine, so if you're having problem, I'd refer you to AliSoftware's comment about making sure to clean your build. But if you look to the left of the method name, showDev, you'll see a solid bullet when the IBOutlet is hooked up correctly:
If you compare that to another method, this one, saveMasterEmail is not currently hooked up correctly, evidenced by the empty circle to the left of the method:
Unrelated, your code:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewControllerDev *dev = (ViewControllerDev *) [storyboard instantiateViewControllerWithIdentifier:#"dev"];
[self presentModalViewController:dev animated:YES];
could be simplified to:
UIViewController *dev = [self.storyboard instantiateViewControllerWithIdentifier:#"dev"];
[self presentModalViewController:dev animated:YES];
Or, even easier, define a segue for that button and you don't need to do anything with code.
Finally, I'd make sure you avoid circular references between your scenes. You shouldn't be doing a modal segue (or presentViewController or presentModalViewController) from A to B and then again from B to A. If you do a modal segue from A to B, you should call dismissViewControllerAnimated to return back to A. Otherwise, you'll have two instances of A floating around.