I tried to control the num variable through UIStepper, but when I pressed the increase button,
It always start count from 0 not 10,
I am curious what did I miss in my code,
Thank you in advance for any comments
#import "ViewController.h"
int num = 10;
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
- (IBAction)myStepper:(UIStepper *)sender;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_myLabel.text = [NSString stringWithFormat:#"%i", num];
}
- (IBAction)myStepper:(UIStepper *)sender {
num = [sender value];
_myLabel.text = [NSString stringWithFormat:#"%i", num];
}
#end
You're never setting the value of the stepper to num. Either set it in Interface Builder's Attributes Inspector, or create an outlet to your stepper:
#property (weak, nonatomic) IBOutlet UIStepper myStepper;
And then in -viewDidLoad, set it like this:
self.myStepper.value = num
As an aside, I would recommend against using a global variable. I would make a property for num instead.
I have been trying to solve this for many hours. None of the posts I have found anywhere has provided a solution. The problem is the textField is in a subview and I cannot figure out how to make it respond to the Return button to hide the keyboard.
Here is my view controller;
#import <UIKit/UIKit.h>
#import "Combatant.h"
#interface ViewController : UIViewController <CombatantDelegate>
- (IBAction) addView;
- (IBAction) roll;
#end
#import "ViewController.h"
static int startY = 60;
#interface ViewController ()
{
NSMutableArray * customViews;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
customViews = [[NSMutableArray alloc] init];
}
- (IBAction) addView
{
Combatant * thing = [[NSBundle mainBundle] loadNibNamed:#"Combatant" owner:nil options:nil][0];
[self.view addSubview: thing];
thing.center = CGPointMake(self.view.center.x, startY + customViews.count * thing.bounds.size.height);
thing.combatDelegate = self;
[customViews addObject:thing];
}
- (IBAction) roll
{
for (Combatant * cust in customViews)
{
[cust rollWasTapped];
}
}
#end
Here is my custom Class;
#import <UIKit/UIKit.h>
#class Combatant;
#protocol CombatantDelegate <NSObject>
#end
#interface Combatant : UIView <UITextFieldDelegate>
{
IBOutlet UITextField * name;
IBOutlet UITextField * base;
IBOutlet UITextField * die;
IBOutlet UITextField * mod;
IBOutlet UILabel * total;
NSString *value;
int dRoll;
int cBase;
int cMod;
}
#property (nonatomic, strong, readwrite) NSString *value;
#property (nonatomic, strong) IBOutlet UITextField * name;
#property (nonatomic, strong) IBOutlet UITextField * base;
#property (nonatomic, strong) IBOutlet UITextField * die;
#property (nonatomic, strong) IBOutlet UITextField * mod;
#property (nonatomic) IBOutlet UILabel * total;
-(void) rollWasTapped;
-(BOOL) textFieldShouldReturn:(UITextField *)textField;
#property (nonatomic, weak) id<CombatantDelegate> combatDelegate;
-(int) dieRoll;
-(int) convertBase;
-(int) convertMod;
#end
#import "Combatant.h"
#implementation Combatant
#synthesize value;
#synthesize name;
#synthesize base;
#synthesize die;
#synthesize mod;
#synthesize total;
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
}
return self;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[name resignFirstResponder];
return YES;
}
- (void) rollWasTapped;
{
int tot;
tot = [self convertBase] + [self dieRoll] + [self convertMod];
total.text = [NSString stringWithFormat:#"%i", tot];
NSLog(#" totaling %i ", tot);
}
-(int) dieRoll
{
int val = [die.text intValue];
if (val <7 && val >0)
{
NSLog(#" %i die", val);
} else {
NSLog(#" there are no dice");
val = 0; }
int d = 0;
for (int i = 0; i < val; i++) {
d = d + arc4random()%6 + 1;
}
dRoll = d;
NSLog(#"%i die roll result = %i ", val, dRoll);
return dRoll;
}
-(int) convertBase
{
cBase = [base.text intValue];
NSLog(#"base = %i", cBase);
if (cBase > -1 && cBase < 20)
{
return cBase;
}
return 0;
}
-(int) convertMod
{
cMod = [mod.text intValue];
NSLog(#"mod = %i", cMod);
if (cMod > -20 && cMod < 20)
{
return cMod;
}
return 0;
}
- (void) dealloc
{
self.combatDelegate = nil;
}
#end
The code works perfect in every aspect except the keyboard hiding.
In the most basic sense, you want the currently active text field to resignFirstResponder. Your problem seems to be how to access that text field.
edit: the below paragraphs jump topics quickly, as I'm detailing a few possible solutions instead of 1.
Goal: Accessing the Text field.
Solutions:
1) Create a property that exposes the text field on the custom class.
2) Create a function that calls the text field on the custom class.
You have 4 properties exposing the text fields, assuming there are 4 text fields on each view?
In that case, go with creating a function, and in that function, on the view, make sure it calls self.textField1 resign... blah, then self.textField2, just make sure it hits all of them.
Currently you call name resignFirstResponder in the callback. But first let's backtrace a little bit. All textFields call textFieldShouldReturn on their delegate. So make sure all 4 of your text fields have the view as the delegate. Either in interface builder or code, self.name.delegate (or self.name.textFieldDelegate, I forgot exactly) = self; for each one.
Also, remember to call "self.", "name" is something else. Actually self. accesses the property accessor. But the invisible variable it creates is called _name (same thing with an underscore at the beginning, this works for all properties).
Now that we know all your fields are being called correctly, let's get back to the delegate. If you really do want the "currently active, returning" text field to resign its responder, the delegate passes in its object view the textField, so just remember to call resignFirst... on the currently returning field.
[textField resignFirstResponder]
Of course, that belongs in the delegate callback method, since textField does not exist otherwise, lest you access it by its name (self.name, or the others).
Last but not least, put a button behind everything, but large enough to cover the screen, make it call a function. In that function, you can "splay" the call to every text field. Basically, make that function call the "hideTheKeyboard" or whatever you named it (the function that calls resignFirst... on all the fields within the custom view) on every custom view.
It should look like your function with for( view in customViews) but instead of calling roll, it calls your custom function.
Within that function, just because it is a possible solution, you can also do something like
- (IBAction) roll
{
for (Combatant * cust in customViews)
{
[cust.name resignFirstResponder];
[cust.die resignFirstResponder];
// and on for the other 2
}
}
But, as you can tell, the reason you might want that encapsulated into a function that you call is simply for less lines of code/simplicity. It is more important that you understand how and why you can do it either way than finding a solution that works. There are 3 solutions I've listed above (use a property, use a function to access the textField, or use the delegate).
The simplest is the delegate, the most compact is the function, and the most widespread is the property. (There are also limitations to each one). I wanted to give a thorough understanding so you can see them.
Put it in the textFieldDidEndEditing: method
- (void)textFieldDidEndEditing:(UITextField *)textField {
{
[textField resignFirstResponder];
}
In viewDidLoad add this:
name.delegate = self;
Or you can do this in the storyboard in the Connections Inspector, by dragging delegate outlet to your view controller.
PS: In this case, textFieldShouldReturn method should be in the view controller too.
You are using delegate which describes that if it should return or not? and before even you are returning you are sending event to your text field keyboard to return or dismiss which is not possible. please try the code as per mentioned by #soulshined.
- (void)textFieldDidEndEditing:(UITextField *)textField {
{
[textField resignFirstResponder];
}
I'm wondering how to call an IBAction from another IBAction.
What I want to do is when I touch a button on previousPage, the title of the nextPage button to change.
In other words I have these IBActions:
- (IBAction)nextPageButtonItemPressed:(UIBarButtonItem *)sender
{
...
}
- (IBAction)previousParageButtonItemPressed:(UIButton *)sender
{
//This is what i want to do
[self nextPageButtonItemPressed:sender.title = #"Next Page"];
}
I have also created an IBOutlet of previousPage.
#property (strong, nonatomic) IBOutlet UIToolbar *nextPageOutlet;
But I can't find the way to do this.
P.S. The nextPage is a button in UIToolbar.
For this, you need to have your UIButton as an IBOutlet property.
So something like:
#property (nonatomic, retain) IBOutlet UIBarButtonItem *previousButton;
#property (nonatomic, retain) IBOutlet UIBarButtonItem *nextButton;
- (IBAction)nextPageButtonItemPressed:(UIBarButtonItem *)sender
{
...
}
- (IBAction)previousPageButtonItemPressed:(UIBarButtonItem *)sender
{
self.nextButton.title = #"Next Page";
}
I have a UITableViewController with an xib that is being used in a popover. It was working fine until I tried to add a UITapGestureRecognizer to the view. With the tableview wired to the UITapGestureRecognizer as an outlet collection, when the user taps an item in the table, the tap handler fires but the didSelectRowAtIndexPath method of the tableview no longer fires.
What I am trying to do is get the position of the tap so I can throw the next popover up in a reasonable location. Maybe there is a better way to do this?
Heres is what my tableview wiring looks like...
Here is the wiring for the recognizer...
Here is my tap handler, which when wired up, fires fine when the user selects an item.
- (IBAction)tapHandler:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
tapPosition = [sender locationInView:self.view];
}
}
Here is the didselectrowAtIndexPath method. Fires fine unless I wire up the tapGestureRecognizer...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[myPO dismissPopoverAnimated:YES];
[self.delegate popupListItemSelected:self withItemRow:indexPath.row item:[listItems objectAtIndex:indexPath.row]];
}
Here is the applicable part of my interface file. All of the objects are synthesized...
#import <UIKit/UIKit.h>
#protocol PopUpListViewControllerDelegate;
#interface PopUpListViewController : UITableViewController {
id<PopUpListViewControllerDelegate> delegate;
IBOutlet UITableView *poupListTableView;
UIPopoverController *myPO;
NSMutableArray *listItems;
IBOutlet UITapGestureRecognizer *tapRecognizer;
}
#property (assign) id<PopUpListViewControllerDelegate> delegate;
#property (retain, nonatomic) IBOutlet UITableView *poupListTableView;
#property (retain, nonatomic) NSMutableArray *listItems;
#property (retain, nonatomic) IBOutlet UITapGestureRecognizer *tapRecognizer;
- (IBAction)tapHandler:(UITapGestureRecognizer *)sender;
- (CGPoint)getTappedPosition;
#end
One option might be to use the CGPoint from your tap handler and find the corresponding row using the UITableView method:
- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point;
So, everything could potentially be handled by your tapHandler: (warning! untested pseudo-code!)
- (IBAction)tapHandler:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
tapPosition = [sender locationInView:self.view];
// use the appropriate name for your tableView, of course.
CGPoint pointInTable = [sender locationInView:self.tableView];
NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:pointInTable];
[myPO dismissPopoverAnimated:YES];
[self.delegate popupListItemSelected:self withItemRow:indexPath.row item:[listItems objectAtIndex:indexPath.row]];
}
}
I have class ABCD.m, as below
**ABCD.m**
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, strong) NSString *string;
- (void) firstMethod;
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2;
-(void) firstMethod {
// Alloc init button
self.button.enabled = NO;
}
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2 {
self.button.enabled = var1;
self.string = var2;
}
There is another class Test.m(subclass of XCTestCase) to write the unit test cases for ABCD.m
**Test.m** //Sub-class of XCTestCase
//Extension
#interface ABCD.m ()
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, strong) NSString *string;
- (void) firstMethod;
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2;
#end
#interace Test : XCTestCase
- (void)testSomeMethod {
ABCD *abcd = [ABCD alloc] init];
BOOL *var1 = YES;
NSString *var2 = #"StackOverFlow";
[abcd firstMethod];
[abcd setTheButtonWithBool:var1 withString:var2];
nslog(#"Result1 :%hhd", self.abcd.button.isEnabled); -----
nslog(#"Result2: %#", self.abcd.string); -----
// Assert statement
}
OUTPUT:
Result 1: NO
Result 2: StackOverFlow
When i set the property 'string' it is getting set to 'StackOverFlow'. But for UIButton property 'button' it is not getting set to 'NO'.
Why cant I set 'enabled' property of UIButton where as i can set the NSString of ABCD.m from the Test.m class
The problem is simple. You never set the button property on your ABCD instance. There is no code that creates a UIButton and assigns it to the button property.
A call like self.button.enabled = NO is translated to [[self button] setEnabled:NO]. Since you haven't set button, the call to [self button] returns nil. So now you call setEnabled: on a nil object which is basically a no-op.
Add code to create a button and set the button property and the rest of the code will work properly.