UIButton in second View Controller - Touch Up Inside not working (Touch Down does) - iphone

I have created a new project in XCode and used the new Storyboard-feature to create two different View Controllers.
The first View Controller is attached to the main files (ViewController.h, Viewcontroller.m). The second View Controller is attached to it's own set of .h/.m files (NewUserController.m/.h)
Now for the problem which I havent been able to find a solution for in the last hours;
I have added a button the second view controller and attached the button to an IBAction (verifyNumber). When I attach the 'Touched Up Inside' event the IBAction is never fired. However, when I attach the 'Touch Down' everything works fine..
Both View Controller's have got the 'user interaction enabled' selected and apart from the button the second view controller doesn't contain any other elements. Also, my manual performSegueWithIdentifier is working (switch from view1 to view2).
Can anyone spot where it has gone wrong?
The code:
ViewController.m
- (void)firstStartup {
// Future use for getting userID
// Switch to loginview
[self performSegueWithIdentifier:#"segueLogin" sender:self];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Fire firstStartup
[self firstStartup];
}
NewUserController.h
#import <UIKit/UIKit.h>
#interface NewUserController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *inputNumber;
- (IBAction)backgroundTap;
//- (IBAction)verifyNumber;
- (IBAction)verifyNumber:(id)sender;
#end
NewUserController.m
#import "NewUserController.h"
#implementation NewUserController
#synthesize inputNumber;
// Collect User data & Start Request
- (IBAction)verifyNumber:(id)sender; {
inputNumber.text = #"testing";
}
- (IBAction)backgroundTap {
[inputNumber resignFirstResponder];
}
UPDATE
Because of the response of NJones I have tested some more and deleted the gesturerecognizer I had present on the second view. After deleting this recognizer the UIButton works with all events (Touched Up Inside).
Does the recognizer somehow block any 'tap' events to overlaying objects (such as the UIButton)?

I have a few thoughts,
1) Why do you have:
- (IBAction)backgroundTap;
//- (IBAction)verifyNumber;
- (IBAction)verifyNumber:(id)sender;
There is a difference between verifyNumber and verifyNumber:(id)sender and they can both exist at the same time, and both can be connected in the nib.
2) Are you using any UIGestureRecoginzers on the view at all?
3) Is this button a custom button or subclass of UIButton?
4) (I truly don't think this will help solve your problem it's just good practice, and I'm already typing :)) Using a view property to check if a method was called is inconclusive at best. Try putting a log statement in the IBAction method like So:
- (IBAction)verifyNumber:(id)sender; {
NSLog(#"verifyNumber:");
inputNumber.text = #"testing";
}

Related

Storyboard - Creating two different Views in storyboard for the same ViewController

I m new in ios development. I m using storyboard for my application, i am creating a two UIView in one UIViewController, in my first view i have one button, i want to when i click on button, picker view(second View) will display that View have one picker, one done and one cancel button.
Use below code:
// ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
IBOutlet UIView *view1;
IBOutlet UIView *view2;
}
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
view2.hidden=YES;} //initially set view2 as hidden.
//IBAction Methods
- (IBAction)Go_To_SecondView:(id)sender {
view1.hidden=YES;
view2.hidden=NO;}
- (IBAction)done:(id)sender {
//your code
}
- (IBAction)cancel:(id)sender {
//your code
}
Your view Controller Scene should be like this:
Add two views and add the buttons and pickerview .
Use the hidden property set to hidden for second view when view appears.
On button click make the second view appear using hidden set to no and bringToFront methods

Why is my delegation between two vc's not working?

I have two view controllers. My first is my menu which contains my highscore and a button which performs a modal segue to my second view controller which is my game. Whenever my player loses the game if he beat his highscore I want it to update on the menu.
Right now, when my player loses the game, I create a UIAlertView with 2 buttons, the first is main menu and the second is restart. Here is my simplified code with my attempting to update my high score via delegation.
#protocol highScoreProtocol <NSObject>
-(void)updateHighScore:(int) score;
#end
#interface ViewController : UIViewController <UIAlertViewDelegate> //i have this delegate implemented because i have a uiialertview
#property (nonatomic) int score;
#property (nonatomic, weak) id <highScoreProtocol> delegateHighScore;
#implementation ViewController
#synthesize score=_score;
#synthesize delegateHighScore=_delegateHighScore;
-(void)lostGame{
[self.delegateHighScore updateHighScore:self.score]; //this is where i try to call the method that should update my high score if necessary but this doesn't actually work
UIAlertView *losingScreen=[[UIAlertView alloc]initWithTitle:#"Game Over" message:[NSString stringWithFormat:#"Your Score Is %d", self.score] delegate:self cancelButtonTitle:#"Main Menu" otherButtonTitles:#"Restart", nil]; //once the user loses the game i have an alert view show giving the option to either restart the game or go to the main menu where the high score is
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex==0) {
//here i'm segueing back to my main menu because he would have pressed the 'main menu' button [self performSegueWithIdentifier:#"MainMenu" sender:self];
} else if (buttonIndex==1){
//here i just reset my attributes and reset my level because he would have pressed the 'restart button'
}
}
#end
#interface MenuVC : UIViewController <highScoreProtocol>
#property (weak, nonatomic) IBOutlet UILabel *labelHighScore; //the labelhighscore is the highscore number
#end
#implementation MenuVC
- (void)viewDidLoad
{
[super viewDidLoad];
ViewController *vc=[[ViewController alloc]init];
vc.delegateHighScore=self;//here is set the delegate as myself which i think i'm supposed to do for some reason
}
-(void)updateHighScore:(int)score{
if (score>[self.labelHighScore.text integerValue]) {
self.labelHighScore.text=[NSString stringWithFormat:#"%d", score];
}
NSLog(#"does this method even run");
// this is the method that updates the highscore which I want to run
// but it doesn't, notice I even made an 'nslog' to see if the method
// even runs but I never ever even got a log out in the debugger,
// so this method never runs.
}
If I just need a little help, or if I'm doing everything completely wrong and going about this task the wrong way, please say.
This doesn't work because this:
ViewController *vc=[[ViewController alloc]init];
vc.delegateHighScore=self;
Instantiates a NEW viewcontroller, that has completely nothing to do with the one you are interacting with.
I assume you are using storyboards so, create an identifier for your viewcontroller (on the interface builder -> select your viewcontroller -> identity inspector tab -> write a name where it says Storyboard ID)
And then add this instead of the previous code:
ViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
vc.delegateHighScore = self;
Edit:
Add this to your button action (but delete the segue from the interface builder AND delete this code from the viewDidLoad)
ViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
vc.delegateHighScore = self;
[self presentModalViewController:vc animated:YES];
Since you create a local variable, vc, in your viewDidLoad method, this is not the same one that you create in the button method where you create your modal segue. That's not the right place to set the delegate. Set yourself to the delegate in that button method using whatever reference you create (or have) to the instance of ViewController that you're segueing to. If you need more information or a code sample, post that button method, so I can see how you are segueing.
After Edit: Then you should implement prepareForSegue:sender: and do this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[(ViewController *)[segue destinationViewController] setDelegate:self];
}

UIViewController auto rotate not working

I have found quite a lot on this subject but I just can't figure it out. Any help would be massively appreciated!
I have an app set up with a UITabBarController. Within one of the tabs, I am showing a UITableView which is using a UINavigationController to allow for hierarchy. All the tables rotate just fine when the orientation is changed, until I get to what is effectively the final view in the hierarchy.
The final view is not a UITableView, just a basic UIView. But I can not get this page to rotate successfully! I have remade the view from with the absolute basics required and it still doesn't want to work! The code is below but it is currently pretty much a standard template with nothing in it now.
Also, I am not using InterfaceBuilder, and shouldAutorotateToInterfaceOrientation is on all views. This is the only one I am having problems with.
SomeView.h
#import <UIKit/UIKit.h>
#interface SomeView : UIViewController
{
NSString *someID;
NSString *someName;
}
#property(nonatomic,retain) NSString *someID;
#property(nonatomic,retain) NSString *someName;
#end
SomeView.m
#import "SomeView.h"
#import "AppDelegate.h"
#implementation SomeView
#synthesize someID, someName;
-(void)loadView
{
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewDidUnload
{
[super viewDidUnload];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
NSLog(#"willAnimateRotationToInterfaceOrientation");
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)dealloc
{
[super dealloc];
}
#end
UPDATE 10th Nov 2011
I'm still having this issue, however looking through documents and bits this seems to be my problem (http://developer.apple.com/library/ios/#qa/qa1688/_index.html)
The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller.
You may find a situation where shouldAutorotateToInterfaceOrientation is called once at startup for a given view controller but is never called again when the device is rotated. Because view controllers are tightly bound to the views they manage, they are also part of the responder chain used to handle events. View controllers are themselves descendants of the UIResponder class and are inserted into the responder chain between the managed view and its superview. So it is common practice to have one primary view controller in your application as part of the responder chain. You would typically add one primary view controller such as a UINavigationController, UITabBarController or a generic UIViewController to your UIWindow. For example, this is done by calling:
[myWindow addSubview:primaryViewController.view];
If you add an additional view controller's UIView property to UIWindow (at the same level as your primary view controller) via the following:
[myWindow addSubview:anotherController.view];
this additional view controller will not receive rotation events and will never rotate. Only the first view controller added to UIWindow will rotate.
My UITabBarController stopped to autorotate, when I added a new navigationController to it with a tableViewController and didn't notice, that my custom navigation controller's shouldAutorotateToInterfaceOrientation returns YES only for one orientation. The solution is to check shouldAutorotateToInterfaceOrientation function in each Controller inside TabBarController.
May be it will help to somebody.
And I have figured it out...
I was looking at the code which pushes the UIViewController onto the stack and I had not fully initied the UIViewController.

Initialization for ViewController under NavController in TabBarController

I have the relatively common setup of a TabBarController whose tabs contain NavigationControllers which have TableViewControllers as their roots. I'm trying to perform some logic on initialization of one of these TableViewControllers but can't seem to find what init function gets called.
My goal is to add a listener in the TableViewController (that I have subclassed) which can respond to events by updating the navigationController.tabBarItem.badgeVluew property.
I've tried putting code into initWithStyle: as well as init but neither of them end up getting called. I've also tried putting it in viewDidLoad, but that only gets called once the controller actually appears (I need to have it happen as soon as the controller is loaded / as soon as the tab bar item shows up).
Does anyone know where I would put this code for it to happen on initialization of the controller?
Also, this is all set up through interface builder / NIBs. I'm not adding the nav controller or tableviewcontroller manually, which is why it's not clear what init function I need to override.
If you select one of your UITabBarItems in IB, you will see 'View loaded from "YourView"'. Click into this "gray" View. In the Inspector window you will see in the Attributes Tab (the tab on the left) the title and the NIB name which will be loaded (lets call it "YourNibName").
Now select the right tab of the inspector (Identity) and change the Classname (Combo next to Class) to your "YourViewController" class, which you must create in xcode. Don't use the standard ViewController, which is already selected. The InterfaceBuilder loads your nib and attaches it to your ViewController.
Open YourNibName and change FilesOwner's Class (Inspector, right Tab) to "YourViewController", too.
Your TabBar's NIB contains a FilesOwner, too. Create a ViewController for this FilesOwner and set its Class to this Controller (i.e. TabBarController)
In "TabBarController" you can find out which Tab was selected by using this code:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if ([viewController.nibName isEqualToString:#"NIBName1"]){
// Do something here, if you like. (i.e. Save the state in a string or int)
}
if ([viewController.nibName isEqualToString:#"NIBNAme2"]){
// Do something here, if you like. (i.e. Save the state in a string or int)
}
...
}
Here you can do something "global" or preinitialize something. This is ONE thing you can do.
INIT OF YOUR VIEWS:
If you select a Tab and the view (which is handled by YourViewController) will be shown for the first time, "viewDidLoad" will be called in "YourViewController"
- (void)viewDidLoad {
// Here you can add views programatically
[self.view addSubview:myNavigationController.view];
[self.view bringSubviewToFront:myNavigationController.view];
// And if you like, do some INIT here
[super viewDidLoad];
}
I hope this is what your question was about.
Now something about the badge. It's a hack, but works fine for me.
Header file:
Add an outlet to your controller, which is representing your TabBarController:
#interface yourController : UIViewController <UITabBarControllerDelegate> {
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
Connect this outlet in IB with your TabBar.
Implementation:
In your TabBarControllerClass you can overwrite 'initWithNibName':
#synthesize tabBarController;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Do some init here
// select your desired item (it will be loaded)
// then you can assign the badge
tabBarController.selectedIndex = 1;
tabBarController.selectedViewController.tabBarItem.badgeValue = #"222";
// and select the item you will start with
tabBarController.selectedIndex = 0;
// if you like you can add a notification, which you can activate from anywhere else
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(itemBadgeChanged:)
name:#"itemBadgeChangedNotification"
object:nil];
}
return self;
}
if you don't use nib, use '- (void)loadView { ... }' instead.
You are using a subclass of the TabBar controller, maybe you can use 'self.selectedIndex = 1;' instead of 'tabBarController.selectedIndex = 1;', and so on. Just try this out
Hope this helps!

Parent view -> Subview -> button -> subview method

I have a parentview with a ui view on it. This loads a subviewcontroller on viewdidload. The subviewcontroller has a button on it that is linked up on touch up inside to a subviewcontroller method called clicked.
This causes a bad access error to fire and crashes the app. My question is, is this setup possible or do I have to have the method in the parent view? The subview will be loaded in 8 different parentviews so I would like to keep the method in the subview.
What would be the correct way of doing this?
The good approach for this kind of setup is to have a protocol including the click message, a delegate property of type id in the view containing the button and a method in the same view that fires the delegated message like so [self.delegate clicked]. The TouchUpInside event is linked to that method in IB and the parent view set itself as delegate of the subview and conform itself to the protocol. It can sounds a bit tricky but its definitely the proper way to do.
the Protocol
#protocol viewWithButtonDelegate
-(void)buttonClicked:(UIButton*)button inView:(UIView*)view;
#end
in the subview interface
#interface viewWithButton {
...
id<viewWithButtonDelegate> delegate;
}
...
#property (nonatomic, retain) id<viewWithButtonDelegate> delegate
-(void)buttonClicked:(id)sender;
...
#end
in the subview implementation
-(void)buttonClicked:(id)sender {
if([sender class] == [UIButton class]) {
[self.delegate buttonClicked:(UIButton*)sender inView:self]
}
}
the controller interface is declared like this
#interface myController<viewWithButtonDelegate>
and finally in the controller implementation :
-(void)buttonClicked:(UIButton*)button inView:(UIView*)view {
//do something in response to button clicked
}
hope this helps...