Objective-C: EXC_BAD_ACCESS and doesn't respond - objective-c

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];

Related

NSLOG does not work

I try to get info for the array in the console but the NSLOg does not show anything. This is a class where i store data for the app. Here is the code.
#import <Foundation/Foundation.h>
#import "DAObject.h"
#interface DataModel : NSObject
#property (strong, nonatomic) NSArray *array;
#property (strong, nonatomic) NSArray *array2;
#end
and in the .m file
#import "DataModel.h"
#implementation DataModel
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
}
return self;
}
- (NSArray *) _array
{
DAObject *obj1 = [[DACityObject alloc] init];
obj1.name = #"Obj1";
DACityObject *obj2 = [[DACityObject alloc] init];
obj2.name = #"Obj2";
_array = #[ obj1, obj2];
for (int i = 0; i < [_array count]; i++)
{
NSLog(#"Item %d = %#", i, [_array objectAtIndex:i]);
}
return _array;
}
- (NSArray *) array2 {
_array2 = [[NSArray alloc] initWithObjects:#"icon1.png", #"icon2.png",#"icon3.png", nil];
for (int i = 0; i < [_array2 count]; i++) {
NSLog(#"Item %d = %#", i, [_array2 objectAtIndex:i]);
}
return _array2;
}
#end
Where is the problem? I can't figure it out.
You need to access from anywhere to that getters, after that you will see logs.
For example try to do that in your AppDelegate.m
#import "DataModel.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
DataModel *data = [DataModel new];
data.array;
data.array2;
}

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."

Realtime Calculator

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!

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.

Leak on iPad that I don't understand

I've got a leak in my application and I do not know why. Maybe I've got all memory managment thing wrong. In my code I've got UIViewController object which have ivar TelephoneValidator *validator
TelephoneValidator is TelephoneValidator : NSObject
So in my initialization function of UIViewController object (initWithFieldData) I've got:
-(id) initWithFieldData: (NSMutableDictionary*) fieldData
{
...
validatorOptions = [fieldData objectForKey:#"fieldValidator"];
...
}
Now in my viewDidLoad I've got:
- (void)viewDidLoad {
...
if (![validatorOptions respondsToSelector:#selector(isEqualToString:)]) {
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
}
else {
validator = nil;
}
...
}
Basicly if my validatorOptions isn't NSString the validator ivar became TelephoneValidator instance.
In my dealloc:
- (void)dealloc {
if(validator != nil)
{
[validator release];
validator = nil;
}
...
[super dealloc];
}
I've checked a couple of times if dealloc works, and it is. After calling dealloc the validator is released (calling any method on validator after [validator release] gets me exception).
And yet in Instruments it is telling me that TelephoneValidator is leaked. And after double clicking in Instruments the line of code that is highlited is:
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
What am I doing wrong?
UPDATE:
Here is my header information of UIViewController:
#interface GenericViewController : UIViewController <UITextFieldDelegate>{
UIImage *backgroundImage;
NSString *step; // na ktorym kroku jestesmy
id <GenericControllerDelegate> delegate; //delegata z ktorej bedziemy pobierali dane
UITextField *textField;
NSString *fieldName; //nazwa pola (potrzebujemy zeby zapisac do modelu odpowiedni tekst
UILabel *textLabel;
UILabel *stepsLabel;
UILabel *prefixTextLabel;
NSString *fieldPlaceholder;
NSString *textLabelText;
NSString *textLabelTextPl; //w jezyku polskim
NSString *prefixTextLabelText; //w jezyku eng
NSString *prefixTextLabelTextPl; //w jezyku polskim prefix
NSString *fieldRequired;
NSString *keyboardType;
NSString *capitalizeType;
UIButton *button; //forward button
UIButton *button2; //backward button
//to bedzie do przerobienia bo bedziemy mieli tablicje walidatorow a nie jeden walidator
NSString *validatorType;
//maksymalna dlugosc pola
int maxLengthOfTextField;
NSArray* validatorOptions;
TelephoneValidator *validator;
//patientModel
PatientData *patientModel;
}
TelephoneValidator header:
#import <Foundation/Foundation.h>
#import "MAOTranslate.h"
#interface TelephoneValidator : NSObject {
//opcje walidacyjne
NSString *phonePrefix;
NSString *phonePostfix;
int phoneLength;
NSString *message;
NSString *messagePl;
UIAlertView *alertView;
}
-(id) initWithOptions:(NSArray *) optionsArray;
-(void) displayMessage;
-(BOOL) validate: (NSString *) phoneNumber;
#end
TelephoneValidator class:
#import "TelephoneValidator.h"
#implementation TelephoneValidator
//#synthesize phoneNumber;
-(id) initWithOptions:(NSArray *) optionsArray;
{
if(self = [[TelephoneValidator alloc] init])
{
phonePrefix = [optionsArray objectAtIndex:0];
phonePostfix = [optionsArray objectAtIndex:1];
phoneLength = [[optionsArray objectAtIndex:2] intValue];
message = [optionsArray objectAtIndex:3];
messagePl = [optionsArray objectAtIndex:4];
}
else {
self = nil;
}
return self;
}
//wyswietlamy wiadomosc
-(void) displayMessage
{
NSString *displayMsg;
if ([[MAOTranslate getLanguage] isEqualToString:#"pl"]) {
displayMsg = messagePl;
}
else {
displayMsg = message;
}
alertView = [[UIAlertView alloc] initWithTitle:#"Alert" message:displayMsg delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alertView show];
}
-(BOOL) validate: (NSString *) phoneNumber
{
//dlugosc
if ([phoneNumber length] != phoneLength) {
NSLog(#"zla dlugosc");
return NO;
}
NSLog(#"tutaj");
//sprawdzamy prefix
if ([phonePrefix length]!= 0) {
NSLog(#"w srodku ifa");
if ([phoneNumber compare:phonePrefix options:NSLiteralSearch range:NSMakeRange(0, [phonePrefix length])] != 0) {
NSLog(#"zly prefix");
[self displayMessage];
return NO;
}
}
//sprawdzamy postfix
if([phonePostfix length] != 0)
{
if ([phoneNumber compare:phonePostfix options:NSLiteralSearch range:NSMakeRange([phoneNumber length]-[phonePostfix length], [phonePostfix length])] != 0) {
NSLog(#"zly postfix");
[self displayMessage];
return NO;
}
}
//sprawdzamy czy string jest numeryczny
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:phoneNumber];
if (![alphaNums isSupersetOfSet:inStringSet])
{
NSLog(#"zly format ");
[self displayMessage];
return NO;
}
return YES; //zwalidowany poprawnie
}
-(void) dealloc
{
[alertView release];
alertView = nil;
[super dealloc];
}
You need to call [super dealloc] at the end of the dealloc method.
See These both lines
validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
and inside initWithOptions
if(self = [[TelephoneValidator alloc] init])
You are allocing twice the validator, so there is a leak.
Could it be that instruments is pointing to validatorOptions as the source of the leak? Is it a retained property being released at dealloc or not? I can't say for sure, the code you posted is not enough to arrive to a conclusion.
Also, as willcodejavaforfood says, you must always call [super dealloc]; at the end of your dealloc method. No code must come after it.
Edit:
I'm back. But Bruno Domingues got it right already, you are allocating twice, in which case, the first one leaks. You should change your -initWithOptions: code to:
-(id) initWithOptions:(NSArray *) optionsArray;
{
if((self = [super init])){
// ... rest of code is fine
}
return self;
}