IBAction not working - ios

I have a uibarbuttonitem called nextButton in storyboard that goes to another ViewController with a segue. But when I try to add this method on another file:
- (IBAction)nextButtonPressed:(id)sender {
NSLog(#"Hello")
}
the output does not show up on the console. The only way I have gotten the button to display this message is when I take out the segue in the storyboard. When I do that, I add the following method so that on clicking the button the segue is done programmatically:
- (IBAction)nextButtonPressed:(id)sender {
NSLog(#"Hello");
GameDetailsTableViewController *gameDetails = [[GameDetailsTableViewController alloc]init];
[self.navigationController pushViewController: gameDetails animated:YES];
}
But when I do this, the console shows an error:
'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
I need help to figure out how to make sure that the button displays the message and goes to the next view controller on click.

A button can be assigned to either an IBAction method or a segue.
If you use a segue, implement -prepareForSegue:sender: in your controller to run any additional code when the segue is executed. E.g.:
- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
if ([[segue identifier] isEqual:#"gameDetailSegue"])
{
GameDetailsTableViewController* gameDetails = (id)[segue destinationViewController];
gameDetails.cheatMode = self.prefs.cheatModeEnabled;
}
}
If you use an action method then you have to present the view controller manually. You also have to instantiate the view controller from your storyboard:
- (IBAction)nextButtonPressed:(id)sender
{
GameDetailsTableViewController* gameDetails =
[self.storyboard instantiateViewControllerWithIdentifier:#"gameDetailController"]
gameDetails.cheatMode = self.prefs.cheatModeEnabled;
[self.navigationController pushViewController:gameDetails animated:YES];
}
In either case, you must assign identifiers to your segues and view controllers in your storyboard.

Related

Segue is executed twice

I am trying to transition between view controllers with a segue. It is navigating correctly but it is running twice.
Here is my code:
- (IBAction)onActionNext:(id)sender {
if ([[nameField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]isEqualToString:#""]) {
}else if([[emailField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:#""]){
}else if([[mobileField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:#""]){
}else{
[self performSegueWithIdentifier:#"VerifyNext" sender:sender];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"VerifyNext"]) {
// Get destination view
OTPSceneViewController *vc = [segue destinationViewController];
[vc setTitle:#"myapp"];
}
}
If even after commenting this line segue still run then as #mikealter said segue is connected your button. Check if when you check for when you click segue what it highlights.
A button like:
Or A View Controller like:
If you fall in first case that means your segue is connected to a button and, that is the reason why it opens next page even if you comment your code. And 2 times when you keep code(one from storyboard and another from code).
Edit:
If you want to call next page from code only. Remove Segue. Then reconnect it with view controller like:
First, whenever you create a segue (i.example) FROM a Button TO a View Controller, you are creating the link between VC1 and VC2.
If you run your project you will see that the segue works navigating from one VC to the other one.
This means that it already performs the segue, so if you declare an ACTION for your button and make a call to - perform segue... - it will run twice.
Note: if you call performSegueWithIdentifier is probably because you want to pass some data via SENDER. In that case you (obviously) need to call the segue ONCE, so instead of creating the segue from the button to the next VC, (first delete that segue), create a new one FROM the VCOrigin to VCDestination -> there are many ways to do it, but from the Interface Builder is as simple as right click on the top yellow rounded icon and drag&drop on the destinationVC. Don't forget to set the identifier on the Attributes Inspector.
Now, in your button~Action make the call to performSegueWithIdentifier and pass the data.
if you stop storyboard segue use following method:
override func shouldPerformSegueWithIdentifier(identifier: String,sender: AnyObject?) -> Bool {
return false
}
You don't even add
[self performSegueWithIdentifier:#"VerifyNext" sender:sender];
in onActionNext method if you add the segue in storyboard
If you want to navigate to next view controller use above line.
Preparing for the Segue
In order to pass information from one view controller to another using
the UIStoryboardSegue object we’ll need to take advantage of the
current view controller’s prepareForSegue:sender: method.
But If you call both,it calls two times.So make sure that whether you want to pass information or data to next view controller or just navigate the view.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepareForSegue: %#", segue.identifier);
if([segue.identifier isEqualToString:#"VerifyNext"])
{
VerifyNextViewController *verifyNVC = segue.destinationViewController;
verifyNVC.name = #"Prashabt";
verifyNVC.id = #"1234";
}
else if([segue.identifier isEqualToString:#"VerSeg"])
{
AnotherViewController *anotherVC = segue.destinationViewController;
anotherVC.name = #"Sharma";
anotherVC.id = #"3245";
}
}
have a look of this question this may sure rectify
or there is another way to navigate to another view controller using below code.
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"viewControllerName"];
[self.navigationController pushViewController:vc animated:YES];
make sure you give identity to the view controller using identity inspector see image.

Button not responding to selector

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.

Method not working when called from another class

I am trying to call the method addObjectToArray from SecondViewController.m. The NSLog works, however I cannot add "foo" to _myArray (an NSMutableArray that is the data source for the UITableView). If I call [self addObjectToArray] in viewDidLoad, then it works fine.
FirstViewController.m
-(void)addObjectToArray {
[_myArray addObject:#"foo"];
[_myTableView reloadData];
NSLog(#"it works");
}
SecondViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"identifier"]) {
FirstViewController *controller = [segue destinationViewController];
[controller addObjectToArray];
}
}
As per Nofel Mahmood's comment, you are creating two separate instances of FirstViewController, one named firstViewController (created from the storyboard) and one called myObject (created with the 'new' method). You then call the addObjectToArray method on myObject, but you present firstViewController. Your myObject is essentially redundant. Amend your code as follows:
-(IBAction) doSomething:(id)sender {
FirstViewController *firstViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"firstViewController"];
[firstViewController addObjectToArray];
[self presentViewController:firstViewController animated:YES completion:nil];
}
EDIT
Since you want to return to an existing instance of FirstViewController, you need to use an unwind segue. There's a detailed explanation here: what-are-unwind-segues, but in your case:
In FirstViewController, add a new method:
- (IBAction)unwindToFirst:(UIStoryboardSegue *)unwindSegue {
[self addObjectToArray];
}
Then in your storyboard, ctrl-drag from the SecondViewController (or if you prefer, from a specific control in the view) to the green "Exit" icon in the bar below the SecondViewController. You should then select the unwindToFirst action in the small popup that appears.
If you want to use this unwind segue from code, look in the Document Outline on the left hand side of your storyboard for the Unwind Segue you just created. Select this, and then add an identifier in the attributes inspector on the right hand side. You can then call this segue from code using the normal [self performSequeWithIdentifier:...] method.

iOS: Programmatically Push Segue to Multiple View Controllers

I have one original view controller with four destination view controllers. I want to be able to push segue with a navigation controller to ALL of the destination view controllers from the original. I have tried...
- (IBAction)notificationsButtonPushed:(id)sender {
NotificationsViewController *notifications = [[NotificationsViewController alloc]init];
[self.navigationController pushViewController:notifications animated:YES];
}
- (IBAction)messagesButtonPushed:(id)sender {
MessagesViewController *messages = [[MessagesViewController alloc] init];
[self.navigationController pushViewController:messages animated:YES];
}
- (IBAction)settingsButtonPushed:(id)sender {
if (canMessage) {
SettingsViewController *settings = [[SettingsViewController alloc]init];
[self.navigationController pushViewController:settings animated:YES];
}
else {
NSLog(#"Can't Message");
}
}
- (IBAction)previewButtonPushed:(id)sender {
PreviewViewController *preview = [[PreviewViewController alloc]init];
[self.navigationController pushViewController:preview animated:YES];
}
and this just gives me an empty view controller without my UI components.
Note: I also have tired "initWithNidName:" and passed in the storyboardID of each destination view controller and it gives me Error:
'Could not load NIB in bundle: 'NSBundle </var/mobile/Applications/B7E025E5-D7D2-4FFD-B49C-E10DF5E94C44/LifePoints.app> (loaded)' with name 'preview'
I also have tried... (with storyboard segues set to "Push")
- (IBAction)notificationsButtonPushed:(id)sender {
[self performSegueWithIdentifier:#"notifications" sender:self];
}
- (IBAction)messagesButtonPushed:(id)sender {
if (canMessage) {
[self performSegueWithIdentifier:#"messages" sender:self];
}
else {
NSLog(#"Can't Message");
}
}
- (IBAction)settingsButtonPushed:(id)sender {
[self performSegueWithIdentifier:#"settings" sender:self];
}
- (IBAction)previewButtonPushed:(id)sender {
[self performSegueWithIdentifier:#"preview" sender:self];
}
Although this does push the destination view controllers onto the screen with the appropriate segue type, it does not segue to the correct destination view controller. It only seems to segue to the last attached storyboard segue.
Does anyone know how to correctly apply this and have it behave in the form I am looking for?
EDIT
It is important to note I am checking to see if a condition is met the "messagesButtonPushed" method. I am checking to see if user is allowed to message, and if they are, then segue to the VC.
You don't need any code to implement the basic segues.
In your story board ensure that your original view controller is embedded in a navigation controller (Select the original View and select Edit->Embed in->Navigation Controller).
Then you can simply control drag from each of your four buttons to the corresponding destination views, selecting "push" as the segue type. You can then click on the segue icon between the two views to give each segue an identifier.
You can delete your IBAction methods and any actions on the buttons that link to them.
I suggest you complete a Storyboard Tutorial to learn how storyboards and segues work.
If you do want to perform a segue programatically then you can control drag from the yellow view controller icon at the bottom of the view to the destination. You can then invoke the segue with performSegueWithIdentifier as per your second code - In your case your could have two different segues and trigger the store segue or the other one depending on purchase status

Receiver MainVIewController has no segue iOS

Question was solved! See the code at the bottom.
I'd like to pass some data between 2 controllers. I have MainViewController class where GoogleMap is loaded. On click at custom info window for each GMap's marker I want to open new window with place details.
My storyboard is:
Segue was named: showPlaceDetails:
Several methods was written:
- (void) mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker {
[self performSegueWithIdentifier:#"showPlaceDetails" sender: nil];
}
(I also tried to use sender: [marker snippet]).
My prepareForSegue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showPlaceDetails"]) {
//[[segue destinationViewController] setDelegate:self];
PlaceDetailsViewController *destViewController = segue.destinationViewController;
//Pass some data
}
}
But I got the message:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (RelaxInKZViewController) has no segue with identifier 'showPlaceDetails''
I did these steps:
Add New View Controller on storyboard.
Add Objective-C Class called PlaceDetailsViewController.
Change custom class of newly added VC to "PlaceDetailsViewController"
Add that code
Clear Simulator's data and clean project
And nothing. I hope you can help me :)
Thx, Artem.
Mr_bem has adviced me to refuse segues and use pushViewController method. It's good!
UIStoryboard *iPhoneStoryboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
PlaceDetailsViewController *destViewController = [iPhoneStoryboard instantiateViewControllerWithIdentifier:#"PlaceDetailsViewController"];
destViewController.placeData = marker.placeData;
[self.navigationController pushViewController:destViewController animated:NO];
You are using a Push segue, this can only be performed with a navigationController, like:
[self.navigationController performSegueWithIdentifier:#"showPlaceDetails" sender: nil];
Note you should have a navigation controller before your ViewController, the one that pushes.
Or if you want, you can change its type to Modal, everything should work great for you (Y)
UPDATE
Okay, here's what I propose, remove the segue, make the storyboardID of your PlaceDetailsViewController to PlaceDetailsViewController from the IB, and add this code instead
- (void) mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker {
PlaceDetailsViewController *destViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PlaceDetailsViewController"];
[self.navigationController pushViewController:destViewController animated:YES]
se
}
THIS MUST WORK! LOL!
You need to embed your RelaxInKZViewController inside UINavigationController to use push segue. Select RelaxInKZViewController-> from the menu at the top select Editor->Embed In->Navigation Controller. I think that will solve your problem.

Resources