Realtime Calculator - objective-c

For a school assignment I have been told to make a calculator app, the same as the spotlight calculator. It works in realtime and has no buttons for things to begin.
So far this is my code. It is written in a text field with the event Editing Did End. Im pretty sure thats wrong but i can't find an alternative solution. Also i haven't gotten the realtime thing to work so i've kind of reverted to completing the following steps when pressed off the text field.
- (IBAction)Didend_Action:(id)sender {
NSString *list = [Sum_TextField text];
NSArray *listItemsArray = [list componentsSeparatedByString:#" "];
float firstNumber = [[listItemsArray objectAtIndex: 0] floatValue];
NSString *symbol = [listItemsArray objectAtIndex: 1];
float secondNumber = [[listItemsArray objectAtIndex: 2] floatValue];
{
Calculator* calc = [[Calculator alloc] init];
[calc setNum1:firstNumber];
[calc setNum2:secondNumber];
if ([symbol isEqualToString:#"-"])
{
[calc minus];
}
else if ([symbol isEqualToString:#"+"])
{
[calc add];
}
if ([symbol isEqualToString:#"*"])
{
[calc multiply];
}
else if ([symbol isEqualToString:#"/"])
{
[calc divide];
}
[Answer_TextField setText:[NSString stringWithFormat:#"%d", [calc answer]]];
}
}

I think a better way to do it would be to implement the UITextViewDelegate protocol methods like textViewDidChange:. For example, you could do something like this:
- (void)textViewDidChange:(UITextView *)textView {
NSString *currentText = [textview text];
NSArray *currentItems = [currentText componenetsSeparatedByString:#" "];
float result = 0.0;
//If a valid expression is in the text view
if([currentItems count] > 2) {
float num1 = [[currentItems objectAtIndex:0] floatValue];
float num2 = [[currentItems objectAtIndex:2] floatValue];
NSString *operator = [currentItems objectAtIndex:1];
if([operator isEqualToString:#"+"]) {
result = num1 + num2;
answerTextField.text = [NSString stringWithFormat:#"%f", result];
}
else if([operator isEqualToString:#"-"]) {
result = num1 - num2;
answerTextField.text = [NSString stringWithFormat:#"%f", result];
}
else if([operator isEqualToString:#"*"]) {
result = num1 * num2;
answerTextField.text = [NSString stringWithFormat:#"%f", result];
}
else if([operator isEqualToString:#"/"]) {
result = num1 / num2;
answerTextField.text = [NSString stringWithFormat:#"%f", result];
}
else{
answerTextField.text = #"Invalid Operation";
}
}
}
This would be called every time the user edited the text in the text view. It should work, but I didn't test it out. Make sure that in the header of whatever file this code is in, you do this:
#interface yourClassName : yourSuperclass <UITextViewDelegate> {
//Your instance variables
}
//Your method and property declarations
EDIT:
Let's say I put the - (void)textViewDidChange:(UITextView *)textView code in a file called MyClass.m. The file MyClass.m would then look like this:
#implementation MyClass
- (void)textViewDidChange:(UITextView *)textView {
//All the above code goes here
}
- (void)viewDidLoad
{
[super viewDidLoad];
//INCLUDE THESE LINES
Sum_TextField.delegate = self;
Answer_TextField.delegate = self;
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
In the header file (MyClass.h), I would put this:
#interface MyClass : UIViewController <UITextViewDelegate>
//Note: you don't declare - (void)textViewDidChange:(UITextView *)textView in the header file because you are implementing
//a protocol method.
//MAKE SURE SUM_TEXTFIELD AND ANSWER_TEXTFIELD ARE UITEXTVIEWS NOT UITEXTFIELDS
#property (strong, nonatomic) IBOutlet UITextView *Sum_TextField;
#property (strong, nonatomic) IBOutlet UITextView *Answer_TextField;
#end
Hope this helps!

Related

how can i display score in other scene?

I have to show score with SKLabel in gameOverScene. how can i show score in GameOverScene Label? I am tried, please help me.
My game scene codes here. You can see all details about score in down stair.
MyScene.m
#interface MyScene ()<SKPhysicsContactDelegate>
#property NSUInteger score;
#end
-(void)setupUI
{
self.score = 0;
SKLabelNode *scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
scoreLabel.fontColor = [SKColor redColor];
scoreLabel.fontSize = 20.0;
scoreLabel.text = #"SCORE: 0";
scoreLabel.name = #"scoreLabel";
scoreLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
scoreLabel.position = CGPointMake(self.size.width/2, self.size.height - scoreLabel.frame.size.height);
[self addChild:scoreLabel];
}
-(void)adjustScoreBy:(NSUInteger)points {
self.score += points;
SKLabelNode* score = (SKLabelNode*)[self childNodeWithName:#"scoreLabel"];
score.text = [NSString stringWithFormat:#"SCORE: %lu", (unsigned long)self.score];
}
- (void)gameOver
{
GameOverScene *gameOverScene = [GameOverScene sceneWithSize:self.size];
[self.view presentScene:gameOverScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
GameOverScene.h
#interface GameOverScene : SKScene
#property NSUInteger *score;
#end
GameOverScene.m
#implementation GameOverScene
{
SKLabelNode *scoreLabel;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.backgroundColor = [SKColor colorWithRed:1.5 green:1.0 blue:0.5 alpha:0.0];
[self addStartButton];
[self addRateButton];
[self addBackButton];
[self addScoreLabel];
}
return self;
}
-(void)addScoreLabel
{
scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
scoreLabel.text = [NSString stringWithFormat:#"SCORE: %lu", (unsigned long)self.score];
scoreLabel.position = CGPointMake(500, 50);
scoreLabel.name = #"gameOverScore";
[self addChild:scoreLabel];
}
There are several approaches to do this.
You could use a singleton class to handle that.
Other option would be to create a public score property in GameOverScene, and then pass the score value of MyScene to GameOverScene, something like this:
In GameOverScene.h add a score property
#interface GameOverScene : SKScene
#property NSUInteger score;
#end
Then in you gameOver method set the score value
- (void)gameOver
{
GameOverScene *gameOverScene = [GameOverScene sceneWithSize:self.size];
gameOverScene.score = self.score;
[self.view presentScene:gameOverScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
In GameOverScene create didMoveToView
- (void)didMoveToView:(SKView *)view
{
[self addScoreLabel];
}
You just need a property in your next scene (target class) and call it from (void)gameOver (in the source class)
Add it int your target class like this
#property int score;
then use it like this in your source class
gameOverScene.score = self.score
You will use this kind of stuff a lot for when moving data around.

Calculator App - strange error: 'unrecognized selector sent to instance' when trying to update display

I'm relatively new to Objective-C, so I'm not 100% about everything I'm coding. However, I'm tackling my errors as they happen, and I am getting a run-time error that I'm not sure how to fix. The error claims that an 'unrecognized selector [was] sent to instance.'
- (IBAction) equalsPressed{
self.userIsInTheMiddleOfTypingANumber = NO;
if (self.brain.operationIsPicked) {
[self.brain pushOperand: [self.display.text doubleValue]];
double result = [self.brain performOperation: self.brain.operation];
// The line below this
self.display.text = [NSString stringWithFormat: #"%g", result];
}
}
I'm doing the Calculator app taught by the Stanford professor whose course is posted in iTunes U. However, I edited it to not include an enterPressed command and instead use an altered and more user-friendly 'equalsPressed.' After equalsPressed is finished (meaning when I click the equals sign on the calculator), the error is displayed. Might anyone know what is causing this problem? I already found someone else who has an error very similar to this one, but occurring in a slightly different place. Here are the other code snippets that could help elucidate the problem.
#import "CalculatorBrain.h"
#interface CalculatorBrain()
#property (nonatomic, strong) NSMutableArray *operandStack;
#end
#implementation CalculatorBrain
#synthesize operandStack = _operandStack;
#synthesize operandStackIsEmpty = _operandStackIsEmpty;
#synthesize operationIsPicked = _operationIsPicked;
#synthesize operation = _operation;
- (NSMutableArray *) operandStack {
if (!_operandStack) {
_operandStack =[[NSMutableArray alloc] init];
_operandStackIsEmpty = YES;
_operationIsPicked = NO;
}
return _operandStack;
}
- (void) resetStack {
[self.operandStack removeAllObjects];
self.operandStackIsEmpty = YES;
self.operationIsPicked = NO;
}
- (void) pushOperand : (double) operand{
[self.operandStack addObject: [NSNumber numberWithDouble:operand]];
self.operandStackIsEmpty = NO;
}
- (double) popOperand {
NSNumber *num = [self.operandStack lastObject];
if (num) {[self.operandStack removeLastObject];}
return [num doubleValue];
}
- (double) performOperation : (NSString *) operation{
double result = 0;
double num2 = [self popOperand];
double num1 = [self popOperand];
if ([operation isEqualToString:#"+"])
result = num2 + num1;
else if ([operation isEqualToString:#"-"])
result = num2 - num1;
else if ([operation isEqualToString:#"*"] || [operation isEqualToString:#"x"])
result = num2 * num1;
else if ([operation isEqualToString:#"/"]){
if (num2 == 0)
[self resetStack];
else
result = num2 / num1;
}
[self pushOperand:result];
self.operationIsPicked = NO;
return result;
}
#end
Also, the debugging NSLog that I had print the display in the console works correctly, BUT the display in the Calculator view doesn't actually update (when I used breakpoints to slow the function down).
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController ()
#property (nonatomic) BOOL userIsInTheMiddleOfTypingANumber;
#property (nonatomic, strong) CalculatorBrain *brain;
#end
#implementation CalculatorViewController
#synthesize userIsInTheMiddleOfTypingANumber = _userIsInTheMiddleOfTypingANumber;
#synthesize brain = _brain;
#synthesize display = _display;
- (CalculatorBrain *) brain {
if (!_brain) {
_brain =[[CalculatorBrain alloc] init];
}
return _brain;
}
- (IBAction) digitPressed: (UIButton *)sender {
NSString *digit = [sender currentTitle];
if (self.userIsInTheMiddleOfTypingANumber)
self.display.text = [self.display.text stringByAppendingString: digit];
else {
self.display.text = digit;
self.userIsInTheMiddleOfTypingANumber = YES;
}
}
- (IBAction) clearPressed {
self.userIsInTheMiddleOfTypingANumber = NO;
self.display.text = #"0";
[self.brain resetStack];
}
- (IBAction) equalsPressed {
self.userIsInTheMiddleOfTypingANumber = NO;
if (self.brain.operationIsPicked) {
[self.brain pushOperand: [self.display.text doubleValue]];
double result = [self.brain performOperation: self.brain.operation];
self.display.text = [NSString stringWithFormat: #"%g", result];
NSLog(#"%#",self.display.text);
}
NSLog(#"%#",self.display.text);
}
- (IBAction) operationPressed:(UIButton *) sender {
if (self.userIsInTheMiddleOfTypingANumber) {
[self.brain pushOperand: [self.display.text doubleValue]];
self.brain.operation = [sender currentTitle];
self.brain.operationIsPicked = YES;
self.userIsInTheMiddleOfTypingANumber = NO;
NSLog(#"%#", sender.currentTitle);
}
}
Thank you!
To quote the answer in the comments:
"The full error said that I sent an invalid argument to "[self.brain equalsPressed:]". In reality, equalsPressed takes no argument, but when I was linking the '=' button in my view to its respective method, I forgot to indicate that the function took no arguments. Hence even though the function as I wrote it has no arguments, I told the compiler (to begin with) that it was supposed to take an argument."

key-value coding compliance

I was foolish and didn't test continually as I programmed, so now I'm not sure where the error has crept in. Am working on a programmable calculator. When I run, it crashes before displaying anything and gives me this message:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<CalculatorViewController 0x6a405a0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key description.'
I'd use NSLog to look for the bug, but I don't know where to try it when the crash happens before anything shows up. Thoughts on what I'm doing wrong?
Here's CalculatorViewController.m, with some extra property declarations for unfinished, commented-out code I've omitted:
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController ()
#property (nonatomic) BOOL userIsEnteringNumber;
#property (nonatomic) BOOL numberIsNegative;
#property (nonatomic,strong) CalculatorBrain *brain;
#end
#implementation CalculatorViewController
#synthesize display = _display;
#synthesize descriptionLabel = _descriptionLabel;
#synthesize userIsEnteringNumber = _userIsEnteringNumber;
#synthesize numberIsNegative;
#synthesize brain = _brain;
-(CalculatorBrain *)brain
{
if (!_brain) _brain = [[CalculatorBrain alloc] init];
return _brain;
}
//This adds a pressed digit to the display label.
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = sender.currentTitle;
//Enter digit if it wouldn't create a two-decimal-point case.
NSRange range = [self.display.text rangeOfString:#"."];
if (range.location==NSNotFound || (![digit isEqualToString:#"."]))
if (self.userIsEnteringNumber)
{
self.display.text = [self.display.text stringByAppendingString:digit];
self.descriptionLabel.text = [self.display.text stringByAppendingString:#" "];
}
else
{
self.descriptionLabel.text = [self.descriptionLabel.text stringByAppendingString:digit];
self.descriptionLabel.text = [self.descriptionLabel.text stringByAppendingString:#" "];
if (![sender.currentTitle isEqualToString:#"."])
{
self.display.text = digit;
}
else
{
self.display.text = #"0.";
}
self.userIsEnteringNumber = YES;
}
}
//This sets up an operation.
- (IBAction)operationPressed:(UIButton *)sender
{
if (self.userIsEnteringNumber) [self enterPressed];
NSString *operation = sender.currentTitle;
double result = [self.brain performOperation:operation];
self.display.text = [NSString stringWithFormat:#"%g",result];
{
NSString *descr = [self.brain description];
self.descriptionLabel.text = descr;
}
}
- (IBAction)enterPressed
{
NSCharacterSet *set = [NSCharacterSet decimalDigitCharacterSet];
NSRange range = [self.display.text rangeOfCharacterFromSet:set];
if (range.location==NSNotFound)
{
[self.brain pushOperandAsVariable:self.display.text];
}
else
{
[self.brain pushOperand:[self.display.text doubleValue]];
}
self.userIsEnteringNumber = NO;
}
#end
And here's CalculatorBrain.m:
#import "CalculatorBrain.h"
#interface CalculatorBrain()
#property (nonatomic, strong) NSMutableArray *programStack;
#property (nonatomic,strong)NSDictionary *variableValues;
#end
#implementation CalculatorBrain
#synthesize programStack = _programStack;
#synthesize variableValues = _variableValues;
- (NSMutableArray *)programStack
{
if (!_programStack) _programStack = [[NSMutableArray alloc] init];
return _programStack;
}
- (id)program
{
return [self.programStack copy];
}
//Here are the two types of pushes that the ViewController can implement. First, operand pushes . . .
- (void)pushOperand:(double)operand
{
[self.programStack addObject:[NSNumber numberWithDouble:operand]];
}
//. . . and then variable pushes.
- (void) pushOperandAsVariable:(NSString *)variable
{
//Create dictionary
//Move this later on to ViewController but for now leave where it is....
NSMutableArray *variablesUsed = [[NSMutableArray alloc] init];
NSArray *objects = [[NSArray alloc] initWithObjects:[NSNumber numberWithDouble:3],[NSNumber numberWithDouble:4.1],[NSNumber numberWithDouble:-6],[NSNumber numberWithDouble:4.5298], [NSNumber numberWithDouble:3.14159], nil];
NSArray *keys = [[NSArray alloc] initWithObjects:#"x",#"y",#"z",#"foo", #"π", nil];
NSDictionary *variableValues = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
//Check program for keys
NSNumber *operand;
for (int i=0; i<keys.count; i++)
{
if ([[keys objectAtIndex:i] isEqual:variable])
[variablesUsed addObject:variable];
operand = [variableValues objectForKey:variable];
}
[self.programStack addObject:operand];
}
- (double)performOperation:(NSString *)operation
{
[self.programStack addObject:operation];
return [[self class] runProgram:self.program];
}
+ (double)popOffStack:(NSMutableArray *)stack
{
double result = 0;
id topOfStack = [stack lastObject];
if (topOfStack) [stack removeLastObject];
if ([topOfStack isKindOfClass:[NSNumber class]])
{
result = [topOfStack doubleValue];
}
//Here are the results for various operations.
else if ([topOfStack isKindOfClass:[NSString class]])
{
NSString *operation = topOfStack;
if ([operation isEqualToString:#"+"])
{
result = [self popOffStack:stack] +
[self popOffStack:stack];
}
else if ([#"*" isEqualToString:operation])
{
result = [self popOffStack:stack] *
[self popOffStack:stack];
}
else if ([operation isEqualToString:#"-"])
{
double subtrahend = [self popOffStack:stack];
result = [self popOffStack:stack] - subtrahend;
}
else if ([operation isEqualToString:#"/"])
{
double divisor = [self popOffStack:stack];
if (divisor) result = [self popOffStack:stack] / divisor;
}
else if ([operation isEqualToString:#"sin"])
{
result = sin([self popOffStack:stack]);
}
else if ([operation isEqualToString:#"cos"])
{
result = cos([self popOffStack:stack]);
}
else if ([operation isEqualToString:#"√"])
{
result = sqrt([self popOffStack:stack]);
}
else if ([operation isEqualToString:#"π"])
{
result = M_PI;
}
}
return result;
}
+ (double)runProgram:(id)program
{
//Run program.
NSMutableArray *mutableCopyOfProgram;
if ([program isKindOfClass:[NSArray class]])
{
mutableCopyOfProgram = [program mutableCopy];
return [self popOffStack:mutableCopyOfProgram];
}
else return 0;
}
#end
As always, thanks for your help.
The most common cause of this is that you have a CalculatorViewController object defined in a storyboard or xib file and something in the graphical interface has a link to an outlet on it called "description". Meanwhile, you no longer have a description outlet in the code for that class.
This will usually be fixed by tracking down the stray reference in interface builder and getting rid of it.

iOS RPNCalculatorStanfordVidOne can't figure out why all but one line is working

I am 100% brand new to iOS.
I am watching Stanford U's videos online to learn iOS. I spent hours slowly going through the second video meticulously ensuring I didn't goof on a line of code. Everything was perfect until - Wouldn't ya know it - the LAST minute of coding.
My wife and I spent a good amount of time trying to figure it out but my code matches the professor's as best we can tell. Please help me. I am loving learning through these videos but I can't move on until I have this functioning and take time to review it.
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController()
#property (nonatomic) BOOL userIsInTheMiddleOfEnteringANumber;
#property (nonatomic, strong) CalculatorBrain *brain;
#end
#implementation CalculatorViewController
#synthesize display = _display;
#synthesize userIsInTheMiddleOfEnteringANumber =
_userIsInTheMiddleOfEnteringANumber;
#synthesize brain = _brain;
- (CalculatorBrain *)brain
{
if (!_brain) _brain = [[CalculatorBrain alloc] init];
return _brain;
}
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = sender.currentTitle;
if (self.userIsInTheMiddleOfEnteringANumber)
{
self.display.text = [self.display.text stringByAppendingString:digit];
}
else
{
self.display.text = digit;
self.userIsInTheMiddleOfEnteringANumber = YES;
}
}
- (IBAction)enterPressed
{
[self.brain pushOperand:[self.display.text doubleValue]];
self.userIsInTheMiddleOfEnteringANumber = NO;
}
- (IBAction)operationPressed:(id)sender
{
if (self.userIsInTheMiddleOfEnteringANumber) [self enterPressed];
double result = [self.brain performOperation:sender.currentTitle]; // <- HERE IS THE LINE IN QUESTION
NSString *resultString = [NSString stringWithFormat:#"%g", result];
self.display.text = resultString;
}
#end
CalculatorBrain.m
#import "CalculatorBrain.h"
#interface CalculatorBrain()
#property (nonatomic, strong) NSMutableArray *operandStack;
#end
#implementation CalculatorBrain
#synthesize operandStack = _operandStack;
- (NSMutableArray *) operandStack
{
if (_operandStack == nil) _operandStack = [[NSMutableArray alloc] init];
return _operandStack;
}
- (void)pushOperand:(double)operand
{
[self.operandStack addObject:[NSNumber numberWithDouble:operand]];
}
- (double)popOperand
{
NSNumber *operandObject = [self.operandStack lastObject];
if (operandObject) [self.operandStack removeLastObject];
return [operandObject doubleValue];
}
- (double)performOperation:(NSString *)operation
{
double result = 0;
if ([operation isEqualToString:#"+"])
{
result = [self popOperand] + [self popOperand];
}
else if ([#"*" isEqualToString:operation])
{
result = [self popOperand] * [self popOperand];
}
[self pushOperand:result];
return result;
}
#end
I think the problem is with your if statement not closing properly.
- (IBAction)operationPressed:(id)sender
{
if (self.userIsInTheMiddleOfEnteringANumber){ [self enterPressed];
double result = [self.brain performOperation:sender.currentTitle];
NSString *resultString = [NSString stringWithFormat:#"%g", result];
self.display.text = resultString;
}
}
or
- (IBAction)operationPressed:(id)sender
{
if (self.userIsInTheMiddleOfEnteringANumber)
{
[self enterPressed];
}
double result = [self.brain performOperation:sender.currentTitle];
NSString *resultString = [NSString stringWithFormat:#"%g", result];
self.display.text = resultString;
}
Suggest looking at the pdf file of the tutorial for a more concrete code source. Hope that help.

Objective-C: EXC_BAD_ACCESS and doesn't respond

Here's the header file:
#interface calc : NSObject {
IBOutlet NSTextField *tf1;
IBOutlet NSTextField *tf2;
IBOutlet NSTextField *ansr;
int s;
}
- (IBAction)add:(id)sender;
#end
And here's the implementation file:
#implementation calc
- (IBAction)add:(id)sender
{
s = [tf1 intValue] + [tf2 intValue];
[ansr setStringValue:(#"%#", s)];
}
- (void) dealloc {
[tf1 release];
tf1 = nil;
[tf2 release];
tf2 = nil;
[ansr release];
ansr = nil;
[super dealloc];
}
#end
s is an int, not an object.
Try this instead :
- (IBAction)add:(id)sender
{
s = [tf1 intValue] + [tf2 intValue];
[ansr setIntValue:s];
setStringValue: doesn't accept more than one argument like printf and stringWithFormat: does.
You should do something like
s = [tf1 intValue] + [tf2 intValue];
NSString* result = [NSString stringWithFormat:#"%i", s];
[ansr setStringValue:result];