Updating UILabel and clearing it? - objective-c

I have a UILabel that I start at "0" and then as my game progresses I call the below code to add "1" to the score each time a button is pressed. This all works fine.
playerOneScore.text = [NSString stringWithFormat:#"%d",[playerOneScore.text intValue]+1];
My problem is that when the game ends and the user presses the "Replay" button. This replay button sets the label back to "0" by calling this.
playerOneScore.text = #"0";
But then when the game progresses my label jumps from "0" to where it had initially left off + 1. What am I doing wrong here? Not making sense.
Any help would be very grateful! Thank you!
More code requested (simplified):
- (void)viewDidLoad
{
playerOneScore.text = #"0";
}
-(IBAction)touchDown {
if (playerOneTurn == YES) {
if (button1.touchInside == YES) {
playerOneScore.text = [NSString stringWithFormat:#"%d",[playerOneScore.text intValue]+1];
}
}
}
-(void) replayGame {
playerOneScore.text = #"0";
}

Not sure what's going on, but I would suggest using a separate NSInteger property to track the score. Then override the property setter to update the label text.
Add the property to your interface or a private category:
#property (nonatomic, assign) NSInteger score;
Then override the setter:
- (void)setScore:(NSInteger)value {
_score = value;
playerOneScore.text = [NSString stringWithFormat:#"%d", value];
}
Then in your action, update the score and label using the new property:
-(IBAction)touchDown {
if (playerOneTurn == YES) {
if (button1.touchInside == YES) {
self.score += 1;
}
}
}
Note that I haven't compiled or tested this code, but it should be close.
EDIT: fixed typo in setter

Related

How to enable an UISwitch while disabling other two simultaneously

I have 3 UISwitches in my View Controller and each one identifies gender ("Woman, Male, No Gender") that user has to choose.
The behavior I would like to implement is that, when the user taps on a switch to select the gender, the others two have to be disabled simultaneously.
And once the switch is selected, the "Create Profile" button is activated. (screenshots attached)
I'm not able to implement the if condition (or alternatively a switch condition)to do that.
Please help.
This is the code I implemented:
- (IBAction)checkGenderSwitch:(id)sender {
if ([self.femaleGenderSwitch isOn] && (![self.maleGenderSwitch isOn] && ![self.noGenderSwitch isOn])) {
[self enableCreateProfileButton];
} else if ([self.maleGenderSwitch isOn] && (![self.femaleGenderSwitch isOn] && ![self.noGenderSwitch isOn])) {
[self enableCreateProfileButton];
} else if ([self.noGenderSwitch isOn] && (![self.femaleGenderSwitch isOn] && ![self.maleGenderSwitch isOn])) {
[self enableCreateProfileButton];
}else{
[self disableCreateProfileButton];
}
}
Thanks.
Let's reformulate your need:
Every time you change a switch value, you do (in pseudo code):
if (male isOn && female isOff && noGender isOff) { enableButton }
else if (male isOff && female isOn && noGender isOff) { enableButton}
else if (male isOff && female isOff && noGender isOn)) { enableButton }
else { disableButton }
Which could be translated in:
if (onlyMale isOn) { enableButton }
else if (onlyFemale isOn) { enableButton}
else if (onlyNoGender isOn) { enableButton }
else { disableButton }
only... isOn? What about putting them into a NSArray, and count the number of isOn? That should do the trick no? only... isOn is for count = 0 where isOn == true.
Which could be then coded:
NSArray *switches = #[self.femaleGenderSwitch, self.maleGenderSwitch, self.noGenderSwitch];
NSUInteger numberOfSwitchesOn = 0;
for (UISwitch *aSwitch in switches) {
if ([aSwitch isOn]) {
numberOfSwitchesOn += 1;
}
}
if (numberOfSwitchesOn == 1) {
[self enableCreateProfileButton];
} else {
[self disableCreateProfileButton];
}
Now, if you want that when you switchOn a Switch, you switchOff the other two (if needed), which in our case would only be one, it can be done with:
NSArray *switches = #[self.femaleGenderSwitch, self.maleGenderSwitch, self.noGenderSwitch];
BOOL hasASwitchOn = NO;
//We iterate over the switches
for (UISwitch *aSwitch in switches) {
//If the newly set is set to on, we need to disable the other (the one which aren't the same as the sender)
if ((UISwitch *)[sender isOn] && ![sender isEqual:aSwitch]) {
[aSwitch setOn:NO];
hasASwitchOn = YES;
} else if ([aSwitch isOn]) { //Else, we still count the number of isOn
hasASwitchOn = YES;
}
}
if (hasASwitchOn) {
[self enableCreateProfileButton];
} else {
[self disableCreateProfileButton];
}
As has been said in a comment, the disablement requirement is wrong. All three switches need to be enabled at all times. The rule should be simply that only one switch at a time can be on.
The key here is that when you tap a switch, and the IBAction method is called, the sender is that switch.
So just keep a list references to all three switches and if the sender is now on, cycle thru the list and turn off each switch that is not the sender.
(Or use a three part UISegmentedControl which does all this for you automatically; it lets the user choose exactly one of three.)
I would use the tag property of UIView for your three switches, giving each of the three its own, unique tag value: for instance, 0, 1, 2. (You can set that up in Interface Builder, or in code — whichever you prefer.) This makes it trivial to distinguish the three switches.
Then, create one extra property, genders, an array of your three switches:
#interface ViewController ()
#property (nonatomic, weak) IBOutlet UISwitch* femaleGenderSwitch;
#property (nonatomic, weak) IBOutlet UISwitch* maleGenderSwitch;
#property (nonatomic, weak) IBOutlet UISwitch* noGenderSwitch;
#property (nonatomic, strong) NSArray* genders;
#end
In -viewDidLoad set that up:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.genders =
#[[self femaleGenderSwitch], [self maleGenderSwitch], [self noGenderSwitch]];
}
Finally, you can simplify your logic in your action method like this:
- (IBAction)checkGenderSwitch:(id)sender
{
if ([sender isOn]) {
for (id aSwitch in [self genders]) {
if ([aSwitch tag] != [sender tag]) {
[aSwitch setOn:NO animated:YES];
}
}
[self enableCreateProfileButton];
}
else {
[self disableCreateProfileButton];
}
}

Cocoa binding: NSTextField with empty string for zero value

I have NSTextField with placeholder. And it's binded to some integer property. So I want to display empty text in the field (with placeholder shown) when binded integer is zero.
Is it possible to do it?
(Update)
I discovered that this can be done through NSNumberFormatter - it has —(void) setZeroSymbol: (NSString*) string method. Not tried yet this in practice...
You could use an NSValueTransformer.
(Just in case)Create a new class, subclass from NSValueTransformer. In the implementation, add something like this:
+(Class)transformedValueClass {
return [NSString class];
}
-(id)transformedValue:(id)value {
if (value == nil) {
return nil;
} else {
if ([value integerValue] == 0) {
return #"";
} else {
return [NSString stringWithFormat:#"%d", [value stringValue]];
}
}
}
In Interface Builder, select your field, go to the bindings tab, and in the Value Transformer drop down, either select or type in your class name you made. This should prevent you from having to worry about modifying it elsewhere. I'm not 100% positive about it showing the placeholder (I don't have a Mac available right now).
EDIT:
I can confirm that this does indeed work. Here is a link to a github project I made to show how to use it: https://github.com/macandyp/ZeroTransformer
check the integer value before binding, if you are binding at runtime. Try
int i;
if (i == 0)
{
txt.placeholder = #"text";
}
else
{
[txt setStringValue:[NSString stringWithFormat:#"%d",i]];
}
You can not do conditional binding.
You need to create another property that will hold the value based on condition and use that property and bind to textfield.
I am using bindedString and bindedInteger. bindedString is bound to text field.
Whenever some action is performed it is updated.
- (id)init{
self = [super init];
if (self) {
self.bindedString=#"place holder string";
}
return self;
}
- (IBAction)button:(id)sender {
if (self.bindedInteger==0) {
self.bindedString=#"place holder string";
}
else{
self.bindedString=[NSString stringWithFormat:#"%ld",self.bindedInteger];
}
}

After xcode crash some buttons have either empty titles or are partially truncated

This seems to be a partial repost of XCode 4: some button titles not visible in iOS simulation but their question wasn't answered.
Please be gentle, I'm very new to this.
I've implemented a stack-based calculator program as per the stamford lecture series, but some of my buttons show as either empty or half truncated in the simulator. The same buttons will do it every time I run the sim, but if I move any buttons around it changes which ones are affected. It's usually the bottom ones.
First example here: http://i.imgur.com/YpC1f.png - see how the bottom row of buttons don't display correctly? If I make any one of those buttons taller, it will show with no title but all the other four buttons will then show correctly.
I thought it might be too close to the bottom, or those buttons were broken, or similar. So I deleted the whole bottom row, made everything smaller, and then recreated those buttons and now I get four buttons with blank titles and two truncated: http://i.imgur.com/kM1Rb.png
Note that the buttons all still work as expected, it's just the display that isn't right.
Am I doing something wrong? Any advice appreciated.
EDIT: Full code from the controller:
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController()
#property (nonatomic) BOOL userIsInTheMiddleOfEnteringANumber;
#property (nonatomic, strong) CalculatorBrain *brain;
- (void)updateStackDisplay:(NSString *)value;
#end
#implementation CalculatorViewController
#synthesize display = _display;
#synthesize stackDisplay = _stackDisplay;
#synthesize userIsInTheMiddleOfEnteringANumber = _userIsInTheMiddleOfEnteringANumber;
#synthesize brain = _brain;
- (CalculatorBrain *)brain {
if (!_brain) _brain = [[CalculatorBrain alloc] init];
return _brain;
}
- (void)updateStackDisplay:(NSString *)value {
// if there's nothing sent so far, just initialise it
if (self.stackDisplay.text.length == 0) {
self.stackDisplay.text = value;
return;
}
// This part is a little confusing. Extra assignment asked for = to be added to the end of the stack label if an operation was pressed.
// Here I check for = at the end of the label and remove it so it's only displayed once. If "=" is being passed (done by the operation itself), it will be added back on right at the end of this function.
if ([self.stackDisplay.text rangeOfString:#"="].location == (self.stackDisplay.text.length - 1)) {
// .location starts at zero, .length doesn't.
self.stackDisplay.text = [self.stackDisplay.text substringToIndex:[self.stackDisplay.text length]-1];
}
// If we add a space after remove the = we'll end up with double space. Hence the else if, not if.
else if (!self.userIsInTheMiddleOfEnteringANumber) {
self.stackDisplay.text = [self.stackDisplay.text stringByAppendingString:#" "];
}
self.stackDisplay.text = [self.stackDisplay.text stringByAppendingString:value];
}
- (IBAction)digitPressed:(UIButton *)sender {
NSString *digit = sender.currentTitle;
if ([digit isEqualToString:#"."]) {
if ([self.display.text rangeOfString:#"."].location != NSNotFound) {
return;
}
else {
if (!self.userIsInTheMiddleOfEnteringANumber) digit = #"0.";
}
}
[self updateStackDisplay:digit];
if (self.userIsInTheMiddleOfEnteringANumber) {
self.display.text = [self.display.text stringByAppendingString:digit];
}
else {
self.display.text = digit;
self.userIsInTheMiddleOfEnteringANumber = YES;
}
}
- (IBAction)operationPressed:(UIButton *)sender {
if (self.userIsInTheMiddleOfEnteringANumber) [self enterPressed];
[self updateStackDisplay:sender.currentTitle];
[self updateStackDisplay:#"="];
double result = [self.brain performOperation:sender.currentTitle];
NSString *resultString = [NSString stringWithFormat:#"%g", result];
self.display.text = resultString;
}
- (IBAction)enterPressed {
if (self.userIsInTheMiddleOfEnteringANumber) {
self.userIsInTheMiddleOfEnteringANumber = NO;
}
[self.brain pushOperand:[self.display.text doubleValue]];
}
- (IBAction)clearPressed {
self.stackDisplay.text = #"";
[self.brain clearStack];
self.userIsInTheMiddleOfEnteringANumber = NO;
self.display.text = #"0";
}
#end
I got a maybe similar error, where some UIButtons had empty text, although by outputting titleLabel.text got the correct text value. I deleted the Buttons and added them identically to what it has before been in the storyboard. Then it worked.

NSString from a class returning null after assignment?

I have a problem with assigning values to a string and then getting them back. The string is a property of a class, because I need it to carry over to other view controllers. (I have tried Core Data, but it didn't work either and this seemed simpler.)
The class for the strings is this:
.h
#interface GameInformation : NSObject
#property (nonatomic, retain) NSString *word;
#property (nonatomic, retain) NSString *mode;
#end
.m
#implementation GameInformation
#synthesize mode = _mode;
#synthesize word = _word;
#end
Pretty simple. The relevant code in app delegate:
GameInformation *gameInfo = [GameInformation alloc].init;
optionsView.gameInfo = gameInfo;
oneBox.gameInfo = gameInfo;
twoBox.gameInfo = gameInfo;
And so on, until I've got all the controllers covered. Options view is where I set the value for the strings, and test those values.
GameInformation *info = [self gameInfo];
UISegmentedControl *selectMode = [self mode];
UISegmentedControl *gameWord = [self word];
if (selectMode.selectedSegmentIndex == 0)
{
info.mode = #"regular";
} else if (selectMode.selectedSegmentIndex == 1) {
info.mode = #"wordTap";
}
if (gameWord.selectedSegmentIndex == 0)
{
info.word = #"regular";
} else if (gameWord.selectedSegmentIndex == 1) {
info.word = #"hat";
} else if (gameWord.selectedSegmentIndex == 2) {
info.word = #"dog";
} else if (gameWord.selectedSegmentIndex == 3) {
info.word = #"book";
} else if (gameWord.selectedSegmentIndex == 4) {
info.word = #"bus";
} else if (gameWord.selectedSegmentIndex == 5) {
info.word = #"cup";
} else if (gameWord.selectedSegmentIndex == 6) {
info.word = #"pig";
}
NSLog(#"%#", info.mode);
NSLog(#"%#", info.word);
And the log comes out as null when those are passed over. I have tried [info setWord:#"regular"]; and [info setMode#"regular"]; but those didn't work either.
I haven't tried using the strings in the one box, two box, etc. controllers yet, because the test return null.
So. What am I doing wrong? Or am I barking up the wrong tree? And, like I said earlier, trying to use core data for this didn't work and this seemed like a simpler approach.
Thanks in advance!
EDIT:
Thank you all for the quick comments! I did a NSLog on info and it is indeed null. I also changed the declarations to copy instead of retain, and changed the dot notation in the alloc statement. The alloc statement is in the app delegate's didFinsihLaunchingWithOptions. Is that the wrong place?
Thanks again for the help!

Formatting UITextField as a time hh:mm

I want a UITextField to correctly format an inputted number as a time, adding minutes using "shouldChangeCharactersInRange" to obtain this result every time a new number is pressed:
i.e.:
00:00
00:08 = 8 pressed
01:23 = 8 -> 3 pressed
08:30 = 8 -> 3 -> 0 pressed
The UITextField is a subview into a Custom UITableViewCell.
I can't figure out, thanks in advance.
Simple
in the H declare:
#interface ViewController : UIViewController
{
int hh;
int mm;
int ss;
}
#property (strong, nonatomic) IBOutlet UILabel *outputLabel;
#end
In the M
-(void)generateText
{
NSString *hhString;
NSString *mmString;
NSString *ssString;
if (hh < 10){
hhString = [NSString stringWithFormat:#"0%d",hh];
} else {
hhString = [NSString stringWithFormat:#"%d",hh];
}
//
if (mm < 10){
mmString = [NSString stringWithFormat:#"0%d",mm];
} else {
mmString = [NSString stringWithFormat:#"%d",mm];
}
if (ss < 10){
ssString = [NSString stringWithFormat:#"0%d",ss];
} else {
ssString = [NSString stringWithFormat:#"%d",ss];
}
NSString *outputText = [NSString stringWithFormat:#"%#:%#:%#",hhString,mmString,ssString];
NSLog(#"output string = %#",outputText);
outputLabel.text = outputText;
}
-(IBAction)addHH:(id)sender
{
hh = hh +1;
[self generateText];
}
-(IBAction)addMM:(id)sender
{
mm = mm +1;
[self generateText];
}
-(IBAction)addSS:(id)sender
{
ss = ss +1;
[self generateText];
}
In Interface builder use 3 buttons to activate the appropriate IBActions
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITextFieldDelegate_Protocol/UITextFieldDelegate/UITextFieldDelegate.html
Use this delegate method to change the text field accordingly
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// You should already have set some string in the text field
if (/*user input is between 0-9*/) {
NSString *text = /* Format your text */
textFiled.text = text;
// Return NO to disable editing done by the user
// Not required to return here if you always return NO;
return NO;
}
// Return NO if you do not want to let user make any changes, otherwise YES
return YES;
}
I have tested it, but changing the textField.text inside this method may call this recursively and fail. If this is the case, use a flag to keep track of what changes are made by you and what by the user. Return YES if the flag is ON and NO otherwise.