I'm trying to write a calculator program, but I'm running into this error when pressing a particular key that is linked to the function expressionEvaluation. My calculator works fine, but I am trying to add in the ability to use/store variables. For this, I use the expressionEvaluation button. However, as soon as I press the button linked to that method, the whole app crashes, and xcode gives me the error EXC_BAD_ACCESS code=2. I'm new to objective-c, so I'm not sure how to debug this error. As far as I can tell, though, the issue is with the line
double result = [CalculatorBrain evaluateExpression:self.brain.expression usingVariableValues:testValues];
...in my view controller. I set a break point before this line and it didn't crash, but setting it at this line resulted in the crash I'm experiencing.
I tried to cut the code down below, and have included only the things directly linked to the expressionEvaluation button. Thank you for your help!
Here's the .h for my brain method:
// CalculatorBrain.h
#import <Foundation/Foundation.h>
#interface CalculatorBrain : NSObject
- (void) pushOperand:(double)operand;
- (void) setVariableAsOperand:(NSString *)variableName;
- (void) performWaitingOperation;
- (double) performOperation:(NSString *)operation;
#property (readonly) id expression;
+ (double)evaluateExpression: (id)anExpression
usingVariableValues: (NSDictionary *)variables;
+ (NSSet *)variablesInExpression:(id)anExpression;
+ (NSString *)descriptionOfExpression:(id)anExpression;
+ (id)propertyListForExpression:(id)anExpression;
+ (id)expressionForPropertyList:(id)propertyList;
#end
Here's the .m:
// CalculatorBrain.m
#import "CalculatorBrain.h"
#define VARIABLE_PREFIX #"^"
#interface CalculatorBrain()
#property (nonatomic) double operand;
#property (nonatomic, strong) NSString *waitingOperation;
#property (nonatomic) double waitingOperand;
#property (nonatomic) double storedOperand;
#property (nonatomic) NSMutableArray *internalExpression;
#end
#implementation CalculatorBrain
#synthesize operand = _operand; //operand in use
#synthesize waitingOperation = _waitingOperation; //waiting to be computed
#synthesize waitingOperand = _waitingOperand; //waiting to be used
#synthesize storedOperand = _storedOperand; //stored in memory
#synthesize internalExpression = _internalExpression; //private expression stored
#synthesize expression = _expression;
- (id) expression {;
return [NSMutableArray arrayWithArray:self.internalExpression];
}
//here I have instance methods that add objects to the array internalExpression
//these work fine as far as I can tell
+ (double) evaluateExpression:(id)anExpression usingVariableValues:(NSDictionary *)variables {
double result = 0;
int count = [anExpression count];
CalculatorBrain *brain;
for (int i = 0; i < count; i++) {
if([[anExpression objectAtIndex:i] isKindOfClass:[NSNumber class]]) {
double operand = [[anExpression objectAtIndex:i] doubleValue];
[brain pushOperand:operand];
}
if([[anExpression objectAtIndex:i] isKindOfClass:[NSString class]]) {
NSString *string = [anExpression objectAtIndex:i];
if([string characterAtIndex:0] == '^') {
NSString* variable = [NSString stringWithFormat:#"%c",[string characterAtIndex:1]];
double valueOfVariable = [[variables objectForKey:variable] doubleValue];
[brain pushOperand:valueOfVariable];
}
else {
NSString* operator = [anExpression objectAtIndex:i];
result = [brain performOperation:operator];
}
}
}
return result;
}
#end
Here's the .h for my view controller:
// CalcViewController.h
#import <UIKit/UIKit.h>
//view controller for calculator
#interface CalcViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *display; //real-time display
#property (strong, nonatomic) IBOutlet UILabel *miniDisplay; //past display
#property (strong, nonatomic) IBOutlet UILabel *memDisplay; //display stored digits
- (IBAction)digitPressed:(UIButton *)sender; //pressed number
- (IBAction)operandPressed:(UIButton *)sender; //pressed operation
- (IBAction)variablePressed:(UIButton *)sender; //pressed variable
- (IBAction)expressionEvaluation:(UIButton *)sender; //evaluate expression with variables
#end
Here's the .m:
// CalcViewController.m
#import "CalcViewController.h"
#import "CalculatorBrain.h"
#interface CalcViewController ()
#property (nonatomic, strong) CalculatorBrain *brain;
#property (nonatomic) BOOL userIsInTheMiddleOfTypingANumber;
#end
#implementation CalcViewController
- (CalculatorBrain *) brain {
if (!_brain) _brain = [[CalculatorBrain alloc] init];
return _brain;
}
- (IBAction)expressionEvaluation:(UIButton *)sender {
NSDictionary* testValues = [NSDictionary dictionaryWithObjectsAndKeys:#"x", 2, #"y", 3, #"z", 4, nil];
double result = [CalculatorBrain evaluateExpression:self.brain.expression usingVariableValues:testValues];
NSString *resultString = [NSString stringWithFormat:#"%g", result];
self.display.text = resultString;
}
#end
EDIT: Just as a side note, I am not getting any errors, only one warning: incomplete implementation. This is because I haven't finished a couple class methods yet, but I don't think it is causing the crash.
NSDictionary* testValues = [NSDictionary dictionaryWithObjectsAndKeys:#"x", 2, #"y", 3, #"z", 4, nil];
turned out to be the erroneous line. It should have been:
NSDictionary* testValues = [NSDictionary dictionaryWithObjectsAndKeys:#"x", [NSNumber numberWithInt:2], #"y", [NSNumber numberWithInt:3], #"z", [NSNumber numberWithInt:4], nil];
Thanks to everyone who helped!
You will get more information on the code line raising the exception by adding an exception breakpoint in xCode.
Related
I have old project written on Objective-C. Need to do migration to Realm.
I created several objects/classes inheritance from RLMObject. When I do fetching objects only with one main object type (ConnectionRealm) - working fine, but if I do add (only add, not include, not use) to project two or more another classes (inheritance from RLMObject), like as FloorRealm class, APP crash on [ConnectionRealm allObjects] without any errors.
Also ConnectionRealm contains RLMArray of FloorRealm. App still crashing.
(Can`t solve and understand this few days.) Thanks.
Connection Model:
#import <Foundation/Foundation.h>
#import <Realm/Realm.h>
#import "FloorRealm.h"
#interface ConnectionRealm : RLMObject
#property int connectionID;
#property NSString *name;
#property NSString *localIPAddress;
#property NSString *localPort;
#property NSString *remoteIPAddress;
#property NSString *remotePort;
#property NSString *userName;
#property NSString *password;
#property NSString *deviceID;
#property RLMArray <FloorRealm *> *floors;
- (instancetype)initWith:(NSString *)name
localIP:(NSString *)localIPAddress
localPort:(NSString *)lPort
remoteIP:(NSString *)remoteIPAddress
remotePort:(NSString *)rPort
userName:(NSString *)userName
password:(NSString *)password
deviceID:(NSString *)deviceID;
#end
#import "ConnectionRealm.h"
#implementation ConnectionRealm
- (instancetype)initWith:(NSString *)name
localIP:(NSString *)localIPAddress
localPort:(NSString *)lPort
remoteIP:(NSString *)remoteIPAddress
remotePort:(NSString *)rPort
userName:(NSString *)userName
password:(NSString *)password
deviceID:(NSString *)deviceID {
if (self = [super init]) {
self.connectionID = [self incrementID];
self.name = name;
self.localIPAddress = localIPAddress;
self.localPort = lPort;
self.remoteIPAddress = remoteIPAddress;
self.remotePort = rPort;
self.userName = userName;
self.password = password;
self.deviceID = deviceID;
}
return self;
}
+ (NSString *)primaryKey { return #"connectionID"; }
- (int)incrementID {
RLMResults *objects = [ConnectionRealm allObjects];
return self.connectionID = [[objects maxOfProperty:#"connectionID"] intValue] + 1;
}
#end
FloorModel:
#import <Realm/Realm.h>
#interface FloorRealm : RLMObject
#property int floorID;
#property NSInteger floorNumber;
#property NSString *floorName;
- (instancetype)initWith:(NSInteger)floorNumber floorName:(NSString *)name;
#end
RLM_ARRAY_TYPE(FloorRealm)
#import "FloorRealm.h"
#implementation FloorRealm
- (instancetype)initWith:(NSInteger)floorNumber floorName:(NSString *)name {
if (self = [super init]) {
self.floorID = [self incrementID];
self.floorNumber = floorNumber;
self.floorName = name;
}
return self;
}
+ (NSString *)primaryKey { return #"floorID"; }
- (int)incrementID {
RLMResults *objects = [FloorRealm allObjects];
return self.floorID = [[objects maxOfProperty:#"floorID"] intValue] + 1;
}
#end
[SOLVED]
RLM_ARRAY_TYPE(FloorRealm) need put on ConnectionRealm in .h after #includes. But in official docs written another.
Also: #property RLMArray <FloorRealm *><FloorRealm> *floors; instead of #property RLMArray <FloorRealm *> *floors;
I created test project with the same models and seed all errors. Strange, but in original project Xcode not showing this errors.
I am trying to implement the module for setting the map parameters before adding the new marker.
The flow is initialing new SliderViewCOntroller from parent mapViewController. After setting the values at SliderViewController and saving their values, it passes back to the parent mapViewCOntroller with new coordinates added. For the time being, the variable for the coordinates are only the global variables on the mapViewCOntroller
Actually, after saving the parameters, it shows the EXEC_BAD)ACCESS (code=1 , address = 0xc)
The code highlights at the
[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
on the SliderViewController.m
Would you please tell me are there any other alternatives to pass the data back from child viewController to parent ViewController using protocols and delegate ?
The below is my working:
MapViewController.h
#import <MessageUI/MessageUI.h>
#import <GoogleMaps/GoogleMaps.h>
#import <UIKit/UIKit.h>
#import "SliderViewController.h"
#interface MapViewController : UIViewController<GMSMapViewDelegate , SliderViewControllerDelegate>{
}
#property (nonatomic) float verticalSliderValue;
#property (nonatomic) float circleSliderValue;
#end
MapViewController.m
//initiaing
-(void) mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate{
p = coordinate;
SliderViewController * sliderVC = [self.storyboard instantiateViewControllerWithIdentifier:#"SliderViewController"];
sliderVC.view.backgroundColor = [UIColor colorWithWhite:1.0 alpha:1.0];
sliderVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:sliderVC animated:YES completion:NULL];
[sliderVC release];
}
//receiving
- (void)passValue:(float )value1 : (float )valueCiruclar
{
NSLog(#"This was returned from ViewControllerB %ff",value1);
NSLog(#"This was returned from ViewControllerSlider %ff",valueCiruclar);
CheckPoints *myCar=[[CheckPoints alloc] init];
[myCar setState:0];
[myCar setLatitude:p.latitude];
[myCar setLongitude:p.longitude];
NSString* theTextValue = #"Desitnation";
[myCar setDesp:theTextValue];
[array addObject:myCar];
CheckPoints *lastChk = array.lastObject;
[self writeToTextFile:[NSString stringWithFormat:#"%#%#%#%#%#%#", lastChk.getDesp , #"\n",[NSString stringWithFormat:#"%f", lastChk.getLatitude],
#"\n", [NSString stringWithFormat:#"%f", lastChk.getLongitude], #"\n" ]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setFloat:lastChk.getLatitude forKey:#"lati"];
[defaults setFloat:lastChk.getLongitude forKey:#"longi"];
[defaults setObject:lastChk.getDesp forKey:#"desp"];
[defaults synchronize];
for (int i = 0; i < [array count]; i++) {
CheckPoints *current = [array objectAtIndex:i];
if(current.getLatitude != lastChk.getLatitude && current.getLongitude != lastChk.getLongitude){
[current setState:1];
NSString* previousTitle = [NSString stringWithFormat:#"%#%#", #"Checkpoint" ,[NSString stringWithFormat:#"%i", i+1]];
[current setDesp:previousTitle];
}
}
[self addMarkers];
}
SliderViewController.h
#import <UIKit/UIKit.h>
#import "EFCircularSlider.h"
#protocol SliderViewControllerDelegate <NSObject>
- (void)passData:(float )itemVertical : (float )itemCircular ;
#end
#interface SliderViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *uiValue;
#property (strong, nonatomic) IBOutlet UISlider *uiSlider;
#property (strong, nonatomic) IBOutlet UIButton *btnReset;
#property (strong, nonatomic) IBOutlet UILabel *uiValue2;
#property (strong, nonatomic) EFCircularSlider* circularSlider;
#property (nonatomic) float verticalSliderValue;
#property (nonatomic) float circleSliderValue;
#property (nonatomic) id <SliderViewControllerDelegate> delegate;
- (IBAction)reset:(id)sender;
- (IBAction)sliderChange:(id)sender;
- (void)buttonClicked: (id)sender;
#end
SliderViewController.m
- (IBAction)reset:(id)sender {
[self writeToTextFile:valueV :valueC];
self.uiValue.text =[NSString stringWithFormat:#"%.2f" , 0.00];
[self.uiSlider setValue:0.00];
self.uiValue2.text =[NSString stringWithFormat:#"%.2f" , 0.00];
[_circularSlider setCurrentValue:0.0f];
MapViewController * sliderVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MapViewController"];
[self.delegate passData:_uiSlider.value :_circularSlider.currentValue ];
sliderVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
}
I'm currently learning some objective C but still have problems with the syntax and creating objects.
The Situation: I need a two dimensional "personsArray" which contains many personArrays each containing a NSString *name and a NSNumber *amount (double). Finally I want to calculate some stuff with the array data in another view but I'm far apart from that..
My Plan: Creating a NSMutable Object when the program starts. If I click the Button "Add Person", it creates a personArray with two fixed values (later it should grab those of textAreas). Here is my Code:
Person.h
#import <Foundation/Foundation.h>
#interface Person : NSObject{
NSNumber *amount;
NSString *name;
}
- (void) createPersonArray:(double)theAmount withName:(NSString*) aName;
#end
Person.m
#import "Person.h"
#implementation Person
- (void) createPersonArray:(NSNumber*)theAmount withName:(NSString*) aName{
NSArray* personArray = [NSArray arrayWithObjects:theAmount,aName,nil];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak,nonatomic) IBOutlet NSMutableArray *personsArray;
- (IBAction)addPerson:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "Person.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)addPerson:(id)sender {
Person *newPerson;
newPerson = [Person new];
[newPerson createPersonArray:100.00 withName:#"test"];
[_personsArray addObject:newPerson];
}
#end
I know that this wont work, but I don't know how to realize the stuff that I described above. If I build the program, the app starts. if I click the button the debugger jumps to the createPersonArray and outputs "Thread 1: EXC_BAD_ACCESS (code=1,address=0x40590000] and "Unused variable 'personArray'".
I watched many tutorials know but none of them explained this situation.. How must my code be structured to accomplish my goal? Am I on the right path or is it the wrong approach?
greetings
I think if you want save array to MutableArray, you only need create method in ViewController. If you create Person.h, i suggest you should save to MutableArray is Person Object. You can use code below:
Person.h:
#property (nonatomic, strong) NSNumber *amount;
#property (nonatomic, strong) NSString *name;
instead:
NSNumber *amount;
NSString *name;
Person.m:
#implementation Person
#synthesize name;
#synthesize amount;
- (void) createPersonArray:(double)theAmount withName:(NSString*) aName{
amount = [NSNumber numberWithDouble:theAmount];
name = aName;
}
ViewController.h
#property (strong,nonatomic) NSMutableArray *personsArray;
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
_personsArray = [[NSMutableArray alloc]init];
}
- (IBAction)addPerson:(id)sender {
Person *newPerson;
newPerson = [Person new];
[newPerson createPersonArray:100.00 withName:#"test"];
[_personsArray addObject:newPerson];
}
If you don't understand. You can comment below, i will help you.
When you need get contain, you can use:
for (Person *person in _personsArray){
NSLog(#"Amount: %# \n Name: %# \n ",ps.amount,ps.name,);
}
or
for (int i = 0; i< [_personsArray count]; i++){
Person *ps = [_personsArray objectAtIndex:i];
NSLog(#"Amount: %# - Name:%#",ps.amount,ps.name);
}
================================== UPDATE ===========================
double sumAmount = 0;
for (int i = 0; i < [_personsArray count]; i++){
Person *person = [_personsArray objectAtIndex:i];
sumAmount = sumAmount + [person.amount doubleValue];
}
double averageAmount = sumAmount / [_personsArray count];
NSLog(#"%f",averageAmount);
First, personsArray variable is not a outlet. So, remove outlet property and replace weak with strong:
#property (strong,nonatomic) NSMutableArray *personsArray;
Second, need to initialize NSMutableArray before using it, maybe in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
_personsArray = [NSMutableArray new];
}
Let me preface this question by saying that I believe it to be a memory management mistake on my end. I just can't seem to figure out why it is happening.
I have a viewcontroller and a model class named Part.
#import <Foundation/Foundation.h>
#interface Part : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *partType;
#property (nonatomic, strong) NSString *description;
#property (nonatomic, strong) NSNumber *price;
- (id)initWithName:(NSString *)name AndType:(NSString *)type;
#end
In the view controller I have a property set as follows:
#property (nonatomic, strong) Part *part;
In the init function of ViewController I create some static arrays and create objects out of them:
- (id)init {
self = [super init];
self.partList = [[NSMutableArray alloc] init];
NSArray *inputArray = #[#"Part1",
#"Part2",
#"Part3",
#"Part4",
#"Part5",
#"Part6",
#"Part7",
#"Part8"];
NSString *tempType = #"PartCategory";
// Add dummy static data
for (int i = 0; i < [inputArray count]; i++) {
Part *partInput = [[Part alloc] initWithName:[inputArray objectAtIndex:i] AndType:tempType];
//partInput.name = [inputArray objectAtIndex:i];
//partInput.partType = tempType;
NSLog(#"Inserting Part %#", partInput);
[self.partList addObject:partInput];
}
return self;
}
The NSLog I call in that loop returns Inserting Part *nil description* for every part. I just can't track down what is happening here.
EDIT: Here is the initWithName method from Part that the controller uses:
- (id)initWithName:(NSString *)name AndType:(NSString *)type {
if(self = [super init]) {
self.name = name;
self.partType = type;
}
return self;
}
When using %# to print NSObject, it calls debugDescription that by default calling the description method of that object and your Part object always have nil description.
You better solve this by changing the description property name to something else, because it conflicts with the description method of NSObject.
See also: NSObject description and debugDescription
I'm making a Card game and trying to call UIImages from an object's instance variable to update a UIImageView
I have a Deck object, which has an NSArray instance variable of Card objects.
Each Card object has a few instance variables, one of which is an UIImage that I'm trying to display in a UIImageView....and this is where I'm having a problem
The storyboard isn't displaying the UIImageView and i'm not getting any compile errors
The UIImageView that I'm trying to update is cardDisplay (ViewController.h)
Here's some snippets from my code
ViewController.h
#import "Deck.h"
#import "Card.h"
#interface ViewController : UIViewController
{
UIImageView *cardDisplay;
}
#property (nonatomic, retain) IBOutlet UIImageView *cardDisplay;
#end
ViewController.m
#import "ViewController.h"
#import "Deck.h"
#import "Card.h"
#implementation ViewController
#synthesize cardDisplay;
- (void)viewDidLoad
{
[super viewDidLoad];
Deck *deck = [[Deck alloc]init];
NSLog(#"%#", deck);
for (id cards in deck.cards) {
NSLog(#"%#", cards);
}
self.cardDisplay = [[UIImageView alloc] initWithImage:
[[deck.cards objectAtIndex:0 ] cardImage]];
}
#end
Card.h
#interface Card : NSObject
{
NSString *valueAsString, *suitAsString;
NSInteger faceValue, countValue;
Suit suit;
UIImage *cardImage;
}
#property (nonatomic, retain) NSString *valueAsString;
#property (nonatomic, retain) NSString *suitAsString;
#property (nonatomic) NSInteger faceValue;
#property (nonatomic) NSInteger countValue;
#property (nonatomic) Suit suit;
#property (nonatomic) UIImage *cardImage;
- (id) initWithFaceValue:(NSInteger)aFaceValue countValue:(NSInteger)aCountValue
suit:(Suit)aSuit cardImage:(UIImage*)aCardImage;
#end
Deck.h
#import "Card.h"
#interface Deck : NSObject
{
NSMutableArray *cards;
}
#property(nonatomic, retain)NSMutableArray *cards;
#end
Deck.m
#import "Deck.h"
#import "Card.h"
#implementation Deck
#synthesize cards;
- (id) init
{
if(self = [super init])
{
cards = [[NSMutableArray alloc] init];
NSInteger aCount, picNum = 0;
for(int suit = 0; suit < 4; suit++)
{
for(int face = 1; face < 14; face++, picNum++)
{
if (face > 1 && face < 7)
aCount = 1;
else if (face > 6 && face < 10)
aCount = 0;
else
aCount = -1;
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *imagePath = [path stringByAppendingPathComponent:
[NSString stringWithFormat:#"/cards/card_%d.png",picNum]];
UIImage *output = [UIImage imageNamed:imagePath];
Card *card = [[Card alloc] initWithFaceValue:(NSInteger)face
countValue:(NSInteger)aCount
suit:(Suit)suit
cardImage:(UIImage *)output];
[cards addObject:card];
}
}
}
return self;
}
#end
This line:
self.cardDisplay = [[UIImageView alloc] initWithImage:
[[deck.cards objectAtIndex:0 ] cardImage]];
should be:
self.cardDisplay.image = [[deck.cards objectAtIndex:0 ] cardImage];
You need to set the image on the image view you created in IB, not create a new one. Doing it this way doesn't keep you from doing what you want with the timer later.