I am making a simple calculator application that displays the equation that the user has inputed and also the output of the equation. At the top of my header file I created three integers and an array...
#import <UIKit/UIKit.h>
int Method;
int SelectNumber;
float RunningTotal;
NSMutableArray *Equation;
#interface SecondCalculatorViewController : UIViewController{
IBOutlet UILabel *EquationLabel;
IBOutlet UILabel *ResultLabel;
}
- (IBAction)OneButton:(id)sender;
- (IBAction)TwoButton:(id)sender;
- (IBAction)ThreeButton:(id)sender;
- (IBAction)FourButton:(id)sender;
- (IBAction)FiveButton:(id)sender;
- (IBAction)SixButton:(id)sender;
- (IBAction)SevenButton:(id)sender;
- (IBAction)EightButton:(id)sender;
- (IBAction)NineButton:(id)sender;
- (IBAction)ZeroButton:(id)sender;
- (IBAction)Plusbutton:(id)sender;
- (IBAction)MinusButton:(id)sender;
- (IBAction)MultiplyButton:(id)sender;
- (IBAction)DivideButton:(id)sender;
- (IBAction)CalculateButton:(id)sender;
- (IBAction)ClearButton:(id)sender;
#end
In my implementation, I prepare each input to be displayed in a label and then also I try to save SelectNumber into the first index in the array I created. I then try to display it in the label. Here is an example of one of the buttons...
- (IBAction)OneButton:(id)sender {
//[Equation addObject:0];
SelectNumber = SelectNumber * 10;
SelectNumber = SelectNumber + 1;
//EquationLabel.text = [NSString stringWithFormat:#"%i",SelectNumber];
[Equation replaceObjectAtIndex:0 withObject:[NSString stringWithFormat:#"%i",SelectNumber]];
EquationLabel.text = [Equation objectAtIndex:0];
}
When I run this in the simulator and push any number, it does not display the first value in the array "Equation".
How can I fix this?
It seems that Equation is not initialized. You need to initialize it:
Equation = [NSMutableArray new];
// or Equation = [[NSMutableArray alloc] init];
viewDidLoad method could be a good place for this code in your case.
Related
I have made the basic build and it includes a picker. So whatever units of conversion the user selects from the picker, the labels should be updated to show the names of the units for that conversion and once the user enters the number in the text box and hits the button, the answer should be displayed in the second text box. Now the code executes, but the problem is no matter what I pick in the picker, it always does the weight conversion. I know I need a switch statement in there, but I'm not sure how or where I need to implement it.
Another problem is that the labels update, but only when the "Convert" button is pressed, so please help me fix this.
This is my ViewController.h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
<UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UITextField *field1;
IBOutlet UITextField *field2;
IBOutlet UIPickerView *picker;
IBOutlet UILabel *label1;
IBOutlet UILabel *label2;
}
#property (weak, nonatomic) IBOutlet UILabel *textLabelData1;
#property (weak, nonatomic) IBOutlet UILabel *textLabelData2;
#property (nonatomic, retain) UIPickerView *picker;
-(IBAction) currencyConvert:(id)sender;
-(IBAction) weightConvert:(id)sender;
-(IBAction) distanceConvert:(id)sender;
#end
This is my ViewController.m file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize picker;
static NSString *pd[3] = {#"Currency", #"Weight", #"Speed"};
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark UIPickerViewDelegate & UIPickerViewDataSource methods
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
return 3;
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:
(NSInteger)row forComponent:(NSInteger)component;
{
return pd[row];
}
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component
{
NSLog(#"didSelectRow %li, inComponent: %li", row, component);
}
-(IBAction)currencyConvert:(id)sender
{
if (pd[0])
{
self.textLabelData1.text = #"Dollar";
self.textLabelData2.text = #"Rupees";
float dollar = [[field1 text] floatValue];
float rupees = dollar * 64.15;
[field2 setText: [NSString stringWithFormat: #"%3.3f", rupees]];
}
/* self.textLabelData1.text = #"Dollar";
self.textLabelData2.text = #"Rupees";
float dollar = [[field1 text] floatValue];
float rupees = dollar * 64.15;
[field2 setText: [NSString stringWithFormat: #"%3.3f", rupees]]; */
}
-(IBAction)weightConvert:(id)sender
{
if (pd[1])
{
self.textLabelData1.text = #"Kilogram";
self.textLabelData2.text = #"Lbs";
float kilogram = [[field1 text] floatValue];
float pounds = kilogram * 2.20462;
[field2 setText: [NSString stringWithFormat: #"%3.3f", pounds]];
}
}
-(IBAction)distanceConvert:(id)sender
{
if (pd[2])
{
self.textLabelData1.text = #"Mile";
self.textLabelData2.text = #"Kilometer";
float miles = [[field1 text] floatValue];
float kilometers = miles * 1.60934;
[field2 setText: [NSString stringWithFormat: #"%3.3f", kilometers]];
}
}
/* Pseudocode for switch statement
-- I tried doing this here, but it gives me an
error saying that "row" is undefined. I understand that
it is a local variable, but how else would I write the
switch statement?
Also, is the placement of the switch statement appropriate here
or will I need to implement it in a function?
switch (row)
{
case 1:
call currencyConvert
case2:
call weightConvert
case3:
call distanceConvert
}
*/
The link to the picture of my Main.storyboard
This isn't the ideal UI and creates inefficiencies, but its your app. I just wanted to point out that you might want to spend time working on its design and structure.
As for a solution to your problem, I cant fix everything for you, but I'll point out some things to make it easier for you.
The reason your labels are not updating is because you are not updating anything until you hit the convert button. The below function is where you'll get the event for the picker's new row
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component
{
NSLog(#"didSelectRow %li, inComponent: %li", row, component);
}
Try this instead:
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component
{
NSLog(#"didSelectRow %li, inComponent: %li", row, component);
switch (row) {
case 0:
self.textLabelData1.text = #"Dollar";
self.textLabelData2.text = #"Rupees";
break;
case 1:
// and so on
}
}
Your next issue is that you're not telling your "convert" functions what row is currently selected, and your conditional if does nothing.
In obj-c conditional statements used directly on a variable are basically just checks for initialization. if(x) simply means has x been initialized as a variable = true, if not = false. That's probably not the logic you're looking for in this case.
Next, It appears you're trying to link 3 different functions to the same button press? This is where your above if related issue is causing problems, all three functions are firing at the same time... but only one gets the last say. Presumably the one you linked last, though i cant say for sure. I'd suggest a single function that handles the button press and then relays to the correct methods.
Last, you're never telling the functions anything about the state of the picker. You need to set it as an IBOutlet so your variables will have access to it. Then you can use the picker's selected row function to determine which conversion to use.
The things I highlighted will fix your problems, BUT I would highly recommend checking out some tutorials so you'll learn more about why things do what. I'd recommend: https://www.raywenderlich.com/
Hope that helps!
I would like to create a settings page, where it sets/gets the slider value (text Size) from NSUserDefaults, but my app is having none of it. I dont get any errors, it just doesn't want to save. I've commented the code, to help you understand better what I want to do, but it's quite simple. I have a 7-stage slider that has the font sizes, and you can simply slide it to determine what size of font you want - that is the value I want saved throughout the app. But whenever I press back on the navigation bar and open the settings page again, the default size is always 22.
.h
#interface SettingsViewController : UIViewController
#property (strong, nonatomic) IBOutlet UISlider *sizeSlider;
#property (strong, nonatomic) IBOutlet UILabel *sampleText;
#end
.m
#interface SettingsViewController () {
NSArray *numbers;
NSMutableAttributedString *sampleTextString;
int fontSize;
NSUserDefaults *defaults;
}
#end
#implementation SettingsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = #"Settings";
numbers = #[#(10), #(12), #(14), #(16), #(18), #(20), #(22)]; // Text Sizes, these number values represent each slider position
NSInteger numberOfSteps = ((float)[numbers count]-1); // Slider values go from 0 to the number of values in your numbers array
self.sizeSlider.maximumValue = numberOfSteps; // As the slider moves it will continously call the -valueChanged:
self.sizeSlider.minimumValue = 0;
defaults = [NSUserDefaults standardUserDefaults]; //Setting the font to be the current font saved in the system
long textsize = [defaults integerForKey:#"fontSize"];
NSLog(#"textsize: %ld", textsize);
self.sizeSlider.value = textsize; // Set the Slider to whatever font you had set it previously
self.sizeSlider.continuous = YES; // NO makes it call only once you let go
[self.sizeSlider addTarget:self action:#selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
sampleTextString = [[NSMutableAttributedString alloc] initWithString:#"The Quick Brown Fox Jumps Over The Lazy Dog!"];
self.sampleText.attributedText = sampleTextString;
[sampleTextString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:textsize] range:NSMakeRange(0, sampleTextString.length)];
}
-(void)valueChanged:(UISlider *)sender{
NSUInteger index = (NSUInteger)(self.sizeSlider.value + 0.5); // round the slider position to the nearest index of the numbers array
[self.sizeSlider setValue:index animated:NO];
NSNumber *number = numbers[index]; // <-- This numeric value you want
[sampleTextString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:[number floatValue]] range:NSMakeRange(0, sampleTextString.length)];
[defaults setInteger:[number integerValue] forKey:#"fontSize"]; // Saving fontSize to NSUserDefaults
[defaults synchronize];
self.sampleText.attributedText = sampleTextString;
}
#end
Answer comes from rmaddy - Thanks!
I needed to look at the index, rather than the actual value of the array.
NSInteger indexText = [numbers indexOfObject:[NSNumber numberWithInteger:textsize]];
So I put that in, and that returned the index of the slider position I wanted.
My code looks like proper but isEqual used to compare two object is not working. i'm new to iOS. there is no much resource to check. [box2 isEqual:box1] is always gives me No. but it supposed to give Yes. anything wrong in my code, please suggest me the correct thing. thanks in advance. expecting best suggestion .
#import <Foundation/Foundation.h>
#interface Box:NSObject
{
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
}
#property(nonatomic, readwrite) double height; // Property
-(double) volume;
//-(id)initWithLength:(double)l andBreadth:(double)b;
#end
#implementation Box
#synthesize height;
-(id)init
{
self = [super init];
if(self)
{
length = 2.0;
breadth = 3.0;
}
return self;
}
-(double) volume
{
return length*breadth*height;
}
#end
#class Box;
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Box *box1 = [[Box alloc]init]; // Create box1 object of type Box
Box *box2 = [[Box alloc]init];
NSLog (#"hello world");
box1.height = 5.0;
NSLog (#"%ld",[box1 volume]);
if([box2 isEqual:box1])
{
NSLog(#"%b",[box2 isEqual:box1]);
}
[pool drain];
return 0;
}
You have to override isEqual method in your object.
e.g. in your "#implementation Box"
- (BOOL)isEqual:(id)object
{
if ([object isKindOfClass:[Box class]]) {
Box*box = (Box*)object;
return self.height == box.height; // compare heights values
}
return [super isEqual:object];
}
isEqual: works just fine and as documented, but not as you expected.
isEqual: is a property of NSObject. It returns YES if two object pointers are the same, and NO if they are not. If you want a different result, you need to override isEqual for your Box class. Note that the argument to isEqual: could be anything, not just a Box, so you need to be careful.
Obviously you shouldn't declare instance variables put properties, so the code below assumes that. The way your code is written, you will have some confusion with an instance variable height, a property height, and an instance variable _height, which will give you headaches. It also assumes that you are not subclassing Box (for example you could have a coloured box, which should not be equal to a Box with same width, height and breadth).
- (BOOL)isEqual:(id)other
{
if (! [other isKindOfClass:[Box class]]) return NO;
Box* otherBox = other;
return _length == other.length && _breadth == other.breadth
&& _height == other.height;
}
The object of this application is to translate between english and spanish words.
(Checks text input against all array values to see if it's there and then compares that index to the second array, and displays the parallel value).
That part is working. If the word entered does not exist in the array, I am supposed to have a message like 'No translation available' display in the label. My problem is, I can either get the message to display for nothing or everything - rather than just when it is supposed to.
#import "TranslatorViewController.h"
#interface TranslatorViewController ()
#property (weak, nonatomic) IBOutlet UITextField *textField;
#property (weak, nonatomic) IBOutlet UILabel *label;
- (IBAction)translate:(id)sender;
#property (nonatomic, copy) NSArray *english;
#property (nonatomic, copy) NSArray *spanish;
#end
#implementation TranslatorViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_textField.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//make the keyboard go away
-(BOOL) textFieldShouldReturn:(UITextField *)textField {
{[textField resignFirstResponder];}
return YES;
}
- (instancetype)initWithCoder:(NSCoder*)aDecoder { self = [super initWithCoder:aDecoder]; if(self) { // Add your custom init code here
self.english = #[#"phone",
#"dog",
#"sad",
#"happy",
#"crocodile"];
self.spanish = #[#"telefono",
#"perro",
#"triste",
#"felize",
#"cocodrilo"];
} return self; }
- (IBAction)translate:(id)sender {
//loop through the array
NSString *englishWord = self.textField.text;
for (int index=0; index<[self.english count]; index++)
if([[self.english objectAtIndex:index]
isEqualToString:englishWord])
//retrieve the accompanying spanish word if english word exists in the array
{NSString *spanishWord = [self.spanish objectAtIndex:index];
//and display it in the label
self.label.text = spanishWord;}
//Need code to display 'no translation' if word was not found.
}
#end
The simplest way to do this is probably to set the label's text field to "No translation" before entering the loop. If no match is found, the label will never be re-set to anything else.
There are lots of other ways to structure logic to give you this result. I might tighten up that last loop of code by doing this instead:
NSString * englishWord = self.textField.text;
NSUInteger spanishWordIndex = [self.english indexOfObject:englishWord];
if (spanishWordIndex == NSNotFound) {
self.label.text = #"No translation";
} else {
self.label.text = self.spanish[spanishWordIndex];
}
Why not use an NSDictionary?
- (instancetype)initWithCoder:(NSCoder*)aDecoder {
self = [super initWithCoder:aDecoder];
if(self) { // Add your custom init code here
self.translationDict = #{#"phone":#"telefono",
#"dog":#"perro",
#"sad": #"triste",
#"happy": #"felize",
#"crocodile": #"cocodrilo"]; // self.translationDict is an NSDictionary
}
return self;
}
- (IBAction)translate:(id)sender {
NSString *englishWord = self.textField.text;
NSString *spanishWord=self.translationDict[englishWord];
if (spanishWord == nil) {
spanishWord="No Translation";
}
self.label.text=spanishWord;
}
I put
self.label.text = #"No translation available";
before the if statement which is I believe what Ben Zotto was trying to say! I just wasn't sure how to actually do it at first.
I'm a newb with this stuff.
But that did what I needed it to.
Thanks all!
Reformatted the answer to include your entire code. You should be able to just copy paste into your code.
- (IBAction)translate:(id)sender {
NSString *englishWord = self.textField.text;
NSString *spanishWord = #"No translation found.";
for (int index=0; index<[self.english count]; index++)
{
if([[self.english objectAtIndex:index] isEqualToString:englishWord])
{
//retrieve the accompanying spanish word if english word exists in the array
spanishWord = [self.spanish objectAtIndex:index];
}
}
self.label.text = spanishWord;
}
In designing a quiz app I want to compare the answer selected by the user to the correct answer in an sqlite array.
To do this, I want to do the following on viewDidLoad:, load up the correct answer (which is an integer 1,2,3 etc.) and store it as qACorrect variable.
Then on - (IBAction)submit:(id)sender to have it compare the variable qACorrect with qASelected
Could someone help me with the syntax for assigning the value of qACorrect which is imported in the array to the new variable qACorrect? I am using the rest of this code on ViewDidLoad to load up the questions:
- (void)viewDidLoad
{
MySjtQuestionslist * MySJT =[[MySjtQuestionslist alloc] init];
self.SJT = [MySJT getMySjtQuestion];
[self.QuestionText setText:((SjtQuestionlist *) [self.SJT objectAtIndex:0]).SJTQuestion];
[self.labelA setText:((SjtQuestionlist *) [self.SJT objectAtIndex:0]).SJTQuestionA];
[self.labelB setText:((SjtQuestionlist *) [self.SJT objectAtIndex:0]).SJTQuestionB];
[self.labelC setText:((SjtQuestionlist *) [self.SJT objectAtIndex:0]).SJTQuestionC];
[self.labelD setText:((SjtQuestionlist *) [self.SJT objectAtIndex:0]).SJTQuestionD];
[self.labelE setText:((SjtQuestionlist *) [self.SJT objectAtIndex:0]).SJTQuestionE];
[super viewDidLoad];
[scroller setScrollEnabled:YES]; //scrollview stuff
[scroller setContentSize:CGSizeMake(320, 1000)]; //scrollview stuff
}
Based on the assumption that qAVariable is the value selected from the segmented controller. & qACorrect is of NSString Type,
You don't need to implement an extra "submit" method. On segment value change, you can do this.
- (IBAction)onSegmentValueChanged:(UISegmentedControl *)sender
{
NSString *selAnswer= [sender titleForSegmentAtIndex:[sender selectedSegmentIndex]];
if ([selAnswer isEqualToString:qACorrect])
{
score = score + 1;
}
else
{
score = score - 1;
}
}
Update:
for getting integer value, use this:
int qACorrect= [[sender titleForSegmentAtIndex:[sender selectedSegmentIndex]] intValue];
Let me know if more info needed..